Add Django site, Docker packaging, and beta/prod Gitea deploys.
Deploy Beta / unit-tests (push) Successful in 9s
Deploy Beta / docker (push) Successful in 17s
Deploy Beta / deploy-beta (push) Successful in 2m31s

Unignore site/ (was blocked by mkdocs /site rule), add compose/Docker/uv tooling, and split deploys so push to main goes to beta while prod stays manual.
This commit is contained in:
2026-08-08 07:32:55 -05:00
parent 7dca98bbf6
commit 1f7d78de64
204 changed files with 21662 additions and 70 deletions
+46
View File
@@ -0,0 +1,46 @@
{% extends "base.html" %}
{% load static %}
{% block title %}404 · {{ SITE_NAME }}{% endblock %}
{% block body %}
<div class="page">
<section class="section section-single bg-gray-800 primary-overlay" style="background-image: url({% static 'images/bg-image-7.jpg' %});">
<div class="section-single-inner">
<div class="section-single-dummy"></div>
<div class="section-single-main">
<div class="container">
<div class="row row-30">
<div class="col-sm-6 text-center text-sm-left">
<p class="text-extra-large">404</p>
</div>
<div class="col-sm-6">
<div class="section-single-main-content">
<h6 class="title-decorated title-decorated-lg">Page not found</h6>
<p><span class="text-width-2">That page may have moved or the link is outdated. Lets get you back on track.</span></p>
<a class="button button-lg button-primary button-winona" href="{% url 'public:home' %}">Back to home</a>
<a class="button button-lg button-default-outline button-winona" href="{% url 'public:contact' %}" style="margin-left:8px">Contact Monica</a>
</div>
</div>
</div>
</div>
</div>
<div class="footer-minimal section-single-footer">
<div class="container">
<div class="footer-minimal-inner">
<a class="brand" href="{% url 'public:home' %}">
<img src="{% static 'brand/exit_logo.png' %}" alt="EXIT Realty · {{ SITE_NAME }}" width="151" height="44"/>
</a>
<div class="footer-aside-copy" style="text-align:left">
<p class="rights">
<span>&copy;&nbsp;</span><span>{% now "Y" %}</span><span>&nbsp;</span><span>{{ SITE_NAME }} · MKDRealtor.com</span>
</p>
<p class="footer-made-by">
Made by <a href="{{ CREDIT_URL }}" target="_blank" rel="noopener noreferrer">{{ CREDIT_NAME }}</a>
</p>
</div>
</div>
</div>
</div>
</div>
</section>
</div>
{% endblock %}
+34
View File
@@ -0,0 +1,34 @@
{% extends "base.html" %}
{% load static %}
{% block title %}About · {{ SITE_NAME }}{% endblock %}
{% block content %}
<section class="breadcrumbs-custom bg-image context-dark" style="background-image: url({% static 'images/breadcrumbs-image-1.jpg' %});">
<div class="breadcrumbs-custom-inner">
<div class="container breadcrumbs-custom-container">
<div class="breadcrumbs-custom-main">
<h6 class="breadcrumbs-custom-subtitle title-decorated">About</h6>
<h2 class="text-uppercase breadcrumbs-custom-title">Meet Monica</h2>
</div>
<ul class="breadcrumbs-custom-path">
<li><a href="{% url 'public:home' %}">Home</a></li>
<li class="active">About</li>
</ul>
</div>
</div>
</section>
<section class="section section-lg">
<div class="container">
<div class="row row-50 justify-content-center justify-content-lg-between flex-lg-row-reverse">
<div class="col-md-10 col-lg-6 col-xl-5">
<h3 class="text-uppercase">Local realtor,<br>personal service</h3>
<p class="about-subtitle">I help families buy and sell homes with clear communication and marketing that actually reaches people — not just another postcard blast.</p>
<p>This site replaces a costly third-party campaign platform. Visitors reach me through a protected contact form; every inquiry lands in my portal with source tracking so I know which campaigns work.</p>
<a class="button button-lg button-primary button-winona" href="{% url 'public:contact' %}" data-tianji-event="about_cta" data-tianji-event-destination="contact">Work with me</a>
</div>
<div class="col-md-10 col-lg-6 col-xl-6">
<img class="img-responsive" src="{% static 'images/careers-1-570x388.jpg' %}" alt="{{ SITE_NAME }}" width="570" height="388"/>
</div>
</div>
</div>
</section>
{% endblock %}
+163
View File
@@ -0,0 +1,163 @@
{% extends "base.html" %}
{% load static %}
{% block title %}Contact · {{ SITE_NAME }}{% endblock %}
{% block content %}
<section class="breadcrumbs-custom bg-image context-dark" style="background-image: url({% static 'images/breadcrumbs-image-1.jpg' %});">
<div class="breadcrumbs-custom-inner">
<div class="container breadcrumbs-custom-container">
<div class="breadcrumbs-custom-main">
<h6 class="breadcrumbs-custom-subtitle title-decorated">Contact</h6>
<h2 class="text-uppercase breadcrumbs-custom-title">Get in touch</h2>
</div>
<ul class="breadcrumbs-custom-path">
<li><a href="{% url 'public:home' %}">Home</a></li>
<li class="active">Contact</li>
</ul>
</div>
</div>
</section>
<section class="section section-sm">
<div class="container">
<div class="layout-bordered">
{% if CONTACT_PHONE %}
<div class="layout-bordered-item wow-outer">
<div class="layout-bordered-item-inner wow slideInUp">
<div class="icon icon-lg mdi mdi-phone text-primary"></div>
<ul class="list-0"><li><a class="link-default" href="tel:{{ CONTACT_PHONE_TEL }}">{{ CONTACT_PHONE }}</a></li></ul>
</div>
</div>
{% endif %}
{% if CONTACT_EMAIL %}
<div class="layout-bordered-item wow-outer">
<div class="layout-bordered-item-inner wow slideInUp">
<div class="icon icon-lg mdi mdi-email text-primary"></div>
<a class="link-default" href="mailto:{{ CONTACT_EMAIL }}">{{ CONTACT_EMAIL }}</a>
</div>
</div>
{% endif %}
<div class="layout-bordered-item wow-outer">
<div class="layout-bordered-item-inner wow slideInUp">
<div class="icon icon-lg mdi mdi-map-marker text-primary"></div>
<span class="link-default">{{ CONTACT_SERVICE_AREA }}</span>
</div>
</div>
</div>
</div>
</section>
<section class="section bg-gray-100">
<div class="container section-lg">
<div class="row">
<div class="col-lg-8">
<h3 class="text-uppercase">Send a message</h3>
<form class="rd-form" method="post" action="{% url 'public:contact' %}">
{% csrf_token %}
<div class="row row-10">
<div class="col-md-6">
<div class="form-wrap">
<label class="form-label-outside" for="{{ form.first_name.id_for_label }}">First name</label>
{{ form.first_name }}
{{ form.first_name.errors }}
</div>
</div>
<div class="col-md-6">
<div class="form-wrap">
<label class="form-label-outside" for="{{ form.last_name.id_for_label }}">Last name</label>
{{ form.last_name }}
{{ form.last_name.errors }}
</div>
</div>
<div class="col-md-6">
<div class="form-wrap">
<label class="form-label-outside" for="{{ form.email.id_for_label }}">Email</label>
{{ form.email }}
{{ form.email.errors }}
</div>
</div>
<div class="col-md-6">
<div class="form-wrap">
<label class="form-label-outside" for="{{ form.phone.id_for_label }}">Phone</label>
{{ form.phone }}
{{ form.phone.errors }}
</div>
</div>
<div class="col-12">
<p class="form-label-outside" style="margin:8px 0 4px">Mailing address <span style="font-weight:400;color:#6b7280">(optional — for postcards)</span></p>
</div>
<div class="col-12" data-address-autocomplete data-suggest-url="{% url 'address_suggest' %}">
<div class="form-wrap address-ac-wrap">
<label class="form-label-outside" for="{{ form.address_line1.id_for_label }}">Street address</label>
{{ form.address_line1 }}
{{ form.address_line1.errors }}
</div>
<div class="row row-10">
<div class="col-md-6">
<div class="form-wrap">
<label class="form-label-outside" for="{{ form.address_line2.id_for_label }}">Apt / suite</label>
{{ form.address_line2 }}
{{ form.address_line2.errors }}
</div>
</div>
<div class="col-md-6">
<div class="form-wrap">
<label class="form-label-outside" for="{{ form.address_city.id_for_label }}">City</label>
{{ form.address_city }}
{{ form.address_city.errors }}
</div>
</div>
<div class="col-md-6">
<div class="form-wrap">
<label class="form-label-outside" for="{{ form.address_state.id_for_label }}">State</label>
{{ form.address_state }}
{{ form.address_state.errors }}
</div>
</div>
<div class="col-md-6">
<div class="form-wrap">
<label class="form-label-outside" for="{{ form.address_zip.id_for_label }}">ZIP</label>
{{ form.address_zip }}
{{ form.address_zip.errors }}
</div>
</div>
</div>
</div>
<div class="col-12">
<div class="form-wrap">
<label class="form-label-outside" for="{{ form.interest.id_for_label }}">I am interested in</label>
{{ form.interest }}
{{ form.interest.errors }}
</div>
</div>
<div class="col-12">
<div class="form-wrap">
<label class="form-label-outside" for="{{ form.message.id_for_label }}">Message</label>
{{ form.message }}
{{ form.message.errors }}
</div>
</div>
{% if form.captcha %}
<div class="col-12">{{ form.captcha }}{{ form.captcha.errors }}</div>
{% endif %}
</div>
<p style="font-size:13px;color:#6b7280;margin:12px 0 20px;">By submitting, you agree I may contact you about your inquiry by email and SMS (if you provide a phone number). You can change preferences or unsubscribe anytime from links in messages, or reply STOP to SMS.{% if form.captcha %} Protected by reCAPTCHA.{% endif %}</p>
<button class="button button-primary button-winona" type="submit" data-tianji-event="contact_form_submit">Send message</button>
</form>
</div>
</div>
</div>
</section>
{% endblock %}
{% block extra_head %}
<link rel="stylesheet" href="{% static 'css/address-autocomplete.css' %}">
{% endblock %}
{% block tracking_events %}
{% if "sent" in request.GET %}
<script>
if (window.aimlTrackWhenReady) {
window.aimlTrackWhenReady('contact_form_success');
}
</script>
{% endif %}
{% endblock %}
{% block extra_js %}
<script src="{% static 'js/address-autocomplete.js' %}"></script>
{% endblock %}
+81
View File
@@ -0,0 +1,81 @@
{% extends "base.html" %}
{% load static %}
{% block title %}Home · {{ SITE_NAME }}{% endblock %}
{% block content %}
<div class="swiper-container swiper-slider swiper-slider-minimal" data-loop="true" data-slide-effect="fade" data-autoplay="false" data-simulate-touch="true">
<div class="swiper-wrapper">
<div class="swiper-slide" data-slide-bg="{% static 'images/slider-minimal-slide-1-1920x968.jpg' %}">
<div class="container">
<div class="jumbotron-classic-content">
<div class="wow-outer">
<div class="title-docor-text font-weight-bold title-decorated text-uppercase wow slideInLeft text-white">{{ SITE_NAME }} · MKDRealtor.com</div>
</div>
<h1 class="text-uppercase text-white font-weight-bold wow-outer"><span class="wow slideInDown" data-wow-delay=".2s">Your Home,<br>Guided Well</span></h1>
<p class="text-white wow-outer"><span class="wow slideInDown" data-wow-delay=".35s">EXIT Realty Redefined — buying or selling in the metro area with clear advice, strong marketing, and a team that answers the phone.</span></p>
<div class="wow-outer button-outer">
<a class="button button-md button-primary button-winona wow slideInDown" href="{% url 'public:contact' %}" data-wow-delay=".4s" data-tianji-event="hero_cta" data-tianji-event-destination="contact">Start a conversation</a>
</div>
</div>
</div>
</div>
<div class="swiper-slide" data-slide-bg="{% static 'images/slider-minimal-slide-2-1920x968.jpg' %}">
<div class="container">
<div class="jumbotron-classic-content">
<div class="wow-outer">
<div class="title-docor-text font-weight-bold title-decorated text-uppercase wow slideInLeft text-white">Local Market Insight</div>
</div>
<h1 class="text-uppercase text-white font-weight-bold wow-outer"><span class="wow slideInDown" data-wow-delay=".2s">Sell With<br>Confidence</span></h1>
<p class="text-white wow-outer"><span class="wow slideInDown" data-wow-delay=".35s">Pricing strategy, staging guidance, and multi-channel outreach so the right buyers see your listing.</span></p>
<div class="wow-outer button-outer">
<a class="button button-md button-primary button-winona wow slideInDown" href="{% url 'public:about' %}" data-wow-delay=".4s" data-tianji-event="hero_about">Meet Monica</a>
</div>
</div>
</div>
</div>
</div>
<div class="swiper-pagination-outer container">
<div class="swiper-pagination swiper-pagination-primary"></div>
</div>
</div>
<section class="section section-lg">
<div class="container">
<h3 class="text-uppercase text-center wow-outer"><span class="wow slideInDown">How I can help</span></h3>
<div class="row row-50">
<div class="col-md-4 wow-outer">
<article class="box-chloe wow slideInUp">
<div class="box-chloe__icon linearicons-home-icon3"></div>
<div class="box-chloe__main">
<h4 class="box-chloe__title">Buyers</h4>
<p>Neighborhood tours, offer strategy, and negotiation that protects your timeline and budget.</p>
</div>
</article>
</div>
<div class="col-md-4 wow-outer">
<article class="box-chloe wow slideInUp" data-wow-delay=".05s">
<div class="box-chloe__icon linearicons-apartment"></div>
<div class="box-chloe__main">
<h4 class="box-chloe__title">Sellers</h4>
<p>Listing prep, professional marketing, and outreach across email, SMS, postcard, and social.</p>
</div>
</article>
</div>
<div class="col-md-4 wow-outer">
<article class="box-chloe wow slideInUp" data-wow-delay=".1s">
<div class="box-chloe__icon linearicons-chart-growth"></div>
<div class="box-chloe__main">
<h4 class="box-chloe__title">Market guidance</h4>
<p>Honest comps and timing advice — whether you move this season or plan ahead.</p>
</div>
</article>
</div>
</div>
</div>
</section>
<section class="section section-lg bg-gray-100 text-center">
<div class="container">
<h3 class="text-uppercase wow-outer"><span class="wow slideInUp">Ready when you are</span></h3>
<p class="wow-outer"><span class="text-width-1 wow slideInDown">Tell me what you are looking for. I will follow up personally — your message becomes a lead in my private portal.</span></p>
<a class="button button-lg button-primary button-winona" href="{% url 'public:contact' %}" data-tianji-event="home_cta_contact">Contact Monica</a>
</div>
</section>
{% endblock %}
@@ -0,0 +1,56 @@
{% extends "base.html" %}
{% load static %}
{% block title %}Under construction · {{ SITE_NAME }}{% endblock %}
{% block body %}
<div class="page">
<section class="section section-single bg-gray-800 primary-overlay" style="background-image: url({% static 'images/bg-image-4.jpg' %});">
<div class="section-single-inner">
<div class="section-single-dummy"></div>
<div class="section-single-main">
<div class="container">
<div class="row row-30 justify-content-center justify-content-sm-start">
<div class="col-sm-10 col-md-9 col-lg-7 col-xl-6">
<h6 class="title-decorated title-decorated-lg">Were getting ready to launch</h6>
<p>{{ SITE_NAME }} · MKDRealtor.coms new site is almost here. Leave your email and Ill let you know when its live — or reach out now if you need help buying or selling.</p>
<div class="rd-mailform-wrap">
<form class="rd-form form-inline" method="post" action="{% url 'public:under_construction' %}">
{% csrf_token %}
<div class="form-wrap">
<input class="form-input" id="{{ form.email.id_for_label }}" type="email" name="{{ form.email.name }}" required value="{{ form.email.value|default:'' }}">
<label class="form-label" for="{{ form.email.id_for_label }}">Your e-mail</label>
{{ form.email.errors }}
</div>
<div class="form-button">
<button class="button button-primary button-winona" type="submit" data-tianji-event="notify_me_submit">Notify me</button>
</div>
</form>
</div>
<p style="margin-top:20px">
<a class="button button-default-outline button-winona" href="{% url 'public:contact' %}" data-tianji-event="holding_contact">Contact Monica now</a>
</p>
</div>
</div>
</div>
</div>
<div class="footer-minimal section-single-footer">
<div class="container">
<div class="footer-minimal-inner">
<a class="brand" href="{% url 'public:home' %}">
<img src="{% static 'brand/exit_logo.png' %}" alt="EXIT Realty · {{ SITE_NAME }}" width="151" height="44"/>
</a>
<div class="footer-aside-copy" style="text-align:left">
<p class="rights">
<span>&copy;&nbsp;</span><span>{% now "Y" %}</span><span>&nbsp;</span><span>{{ SITE_NAME }} · MKDRealtor.com</span>
{% if CONTACT_PHONE %}<span>&nbsp;·&nbsp;</span><a href="tel:{{ CONTACT_PHONE_TEL }}">{{ CONTACT_PHONE }}</a>{% endif %}
</p>
<p class="footer-made-by">
Made by <a href="{{ CREDIT_URL }}" target="_blank" rel="noopener noreferrer">{{ CREDIT_NAME }}</a>
</p>
</div>
</div>
</div>
</div>
</div>
</section>
</div>
{% endblock %}
@@ -0,0 +1,55 @@
{% extends "base.html" %}
{% block title %}Communication preferences · {{ SITE_NAME }}{% endblock %}
{% block content %}
<section class="section section-lg">
<div class="container" style="max-width:560px;">
<h3 class="text-uppercase">Communication preferences</h3>
{% if not valid %}
<p>This preferences link is invalid or has expired.</p>
<p style="font-size:13px;color:#6b7280;">If you still get messages, reply STOP on SMS or contact Monica directly.</p>
<p style="margin-top:24px">
<a class="button button-primary button-winona" href="{% url 'public:contact' %}">Contact Monica</a>
<a class="button button-gray-bordered button-winona" href="{% url 'public:home' %}">Back to home</a>
</p>
{% else %}
<p>You are subscribed as <strong>{{ identity }}</strong>.</p>
<form method="post" action="{% url 'public:unsubscribe' token=token %}">
{% csrf_token %}
<div class="form-wrap">
<label class="checkbox-inline">
<input type="checkbox" name="consent_email" value="1" {% if prefs.email %}checked{% endif %}>
Email marketing
</label>
</div>
<div class="form-wrap">
<label class="checkbox-inline">
<input type="checkbox" name="consent_sms" value="1" {% if prefs.sms %}checked{% endif %}>
SMS updates
</label>
</div>
<div class="form-wrap">
<label class="checkbox-inline">
<input type="checkbox" name="consent_postcard" value="1" {% if prefs.postcard %}checked{% endif %}>
Postcard mailings
</label>
</div>
<p style="font-size:13px;color:#6b7280;margin-top:16px;">
SMS: reply <strong>STOP</strong> anytime. Changes take effect immediately.
Postcard mailings also need a postal address on file.
</p>
<div style="margin-top:24px;display:flex;flex-wrap:wrap;gap:12px;">
<button class="button button-primary button-winona" type="submit" name="action" value="save">
Save preferences
</button>
<button class="button button-gray-bordered button-winona" type="submit" name="action" value="unsubscribe_all">
Unsubscribe from all
</button>
</div>
</form>
<p style="margin-top:32px">
<a class="button button-gray-bordered button-winona" href="{% url 'public:home' %}">Back to home</a>
</p>
{% endif %}
</div>
</section>
{% endblock %}