feat: Adds privacy policy.
All checks were successful
CI / Linux Tests (push) Successful in 8m30s

This commit is contained in:
2026-02-10 16:26:23 -05:00
parent dc9f51c04f
commit 08e67ce308
12 changed files with 1225 additions and 6 deletions

View File

@@ -21,7 +21,6 @@ struct ViewControllerTests {
$0.auth = .failing
} operation: {
@Dependency(\.viewController) var viewController
let home = try await viewController.view(.test(.home))
assertSnapshot(of: home, as: .html)
}
@@ -39,6 +38,18 @@ struct ViewControllerTests {
}
}
@Test
func privacyPolicy() async throws {
try await withDependencies {
$0.viewController = .liveValue
$0.auth = .failing
} operation: {
@Dependency(\.viewController) var viewController
let view = try await viewController.view(.test(.privacyPolicy))
assertSnapshot(of: view, as: .html)
}
}
@Test
func login() async throws {
try await withDependencies {

View File

@@ -33,7 +33,10 @@
<main class="flex flex-col min-h-screen min-w-full grow mb-auto">
<dialog id="loginForm" class="modal modal-open">
<div class="modal-box">
<h1 class="text-2xl font-bold mb-6">Login</h1>
<div class="flex justify-between">
<h1 class="text-2xl font-bold mb-6">Login</h1>
Privacy Policy<a class="btn btn-link" href="/privacy-policy" target="_blank"></a>
</div>
<form method="post" class="space-y-4">
<div>
<label class="input validator w-full"> <svg class="h-[1em] opacity-50" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">

View File

@@ -0,0 +1,475 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Duct Calc</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta content="ductcalc.com" name="og:site_name">
<meta content="Duct Calc" name="og:title">
<meta content="Duct sizing based on ACCA, Manual-D." name="description">
<meta content="Duct sizing based on ACCA, Manual-D." name="og:description">
<meta content="/images/mand_logo.png" name="og:image">
<meta content="/images/mand_logo.png" name="twitter:image">
<meta content="Duct Calc" name="twitter:image:alt">
<meta content="summary_large_image" name="twitter:card">
<meta content="1536" name="og:image:width">
<meta content="1024" name="og:image:height">
<meta content="duct, hvac, duct-design, duct design, manual-d, manual d, design" name="keywords">
<script src="https://unpkg.com/htmx.org@2.0.8"></script>
<script src="/js/htmx-download.js"></script>
<script src="/js/main.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4"></script>
<link rel="stylesheet" href="/css/output.css">
<link rel="stylesheet" href="/css/htmx.css">
<link rel="icon" href="/images/favicon.ico" type="image/x-icon">
<link rel="icon" href="/images/favicon-32x32.png" type="image/png">
<link rel="icon" href="/images/favicon-16x16.png" type="image/png">
<link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon.png">
<link rel="manifest" href="/site.webmanifest">
<script src="https://unpkg.com/htmx-remove@latest" crossorigin="anonymous" integrity="sha384-NwB2Xh66PNEYfVki0ao13UAFmdNtMIdBKZ8sNGRT6hKfCPaINuZ4ScxS6vVAycPT"></script>
</head>
<body>
<div class="flex flex-col min-h-screen min-w-full justify-between" data-theme="default">
<main class="flex flex-col min-h-screen min-w-full grow mb-auto">
<div class="p-10 space-y-4">
<h1 class="text-3xl font-bold">Privacy Policy</h1>
<p>Last updated: February 10, 2026</p>
<p>
This Privacy Policy describes Our policies and procedures on the collection, use and disclosure
of Your information when You use the Service and tells You about Your privacy rights and how the
law protects You.
</p>
<p>
We use Your Personal Data to provide and improve the Service. By using the Service, You agree
to the collection and use of information in accordance with this Privacy Policy. This Privacy
Policy has been created with the help of the<a href="https://www.termsfeed.com/privacy-policy-generator/" target="_blank"> TermsFeed Privacy Policy Generator</a>
</p>
<h2 class="text-2xl font-bold">Interpretation and Definitions</h2>
<h3 class="text-xl font-bold">Interpretation</h3>
<p>
The words whose initial letters are capitalized have meanings defined under the
following conditions. The following definitions shall have the same meaning
regardless of whether they appear in singular or in plural.
</p>
<h3 class="text-xl font-bold">Definitions</h3>
<p>For the purposes of this Privacy Policy:</p>
<ul class="list-disc px-6 space-y-2">
<li><span class="font-bold">Account</span> means a unique account created for You to access our Service or parts of our Service.</li>
<li>
<span class="font-bold">Affiliate</span> means an entity that controls, is controlled by, or is under common control with a
party, where "control" means ownership of 50% or more of the shares, equity interest or other
securities entitled to vote for election of directors or other managing authority.
</li>
<li>
<span class="font-bold">Company</span> (referred to as either "the Company", "We", "Us" or "Our" in this Privacy Policy)
refers to Duct Calc.
</li>
<li>
<span class="font-bold">Cookies</span> are small files that are placed on Your computer, mobile device or any other device by
a website, containing the details of Your browsing history on that website among its many uses.
</li>
<li><span class="font-bold">Country</span> refers to: Ohio, United States</li>
<li>
<span class="font-bold">Device</span> means any device that can access the Service such as a computer, a cell phone or a
digital tablet.
</li>
<li>
<span class="font-bold">Personal Data</span> (or "Personal Information") is any information that relates to an identified or
identifiable individual.
We use "Personal Data" and "Personal Information" interchangeably unless a law uses a specific
term.
</li>
<li><span class="font-bold">Service</span> refers to the Website.</li>
<li>
<span class="font-bold">Service Provider</span> means any natural or legal person who processes the data on behalf of the
Company. It refers to third-party companies or individuals employed by the Company to facilitate
the Service, to provide the Service on behalf of the Company, to perform services related to the
Service or to assist the Company in analyzing how the Service is used.
</li>
<li>
<span class="font-bold">Usage Data</span> refers to data collected automatically, either generated by the use of the Service
or from the Service infrastructure itself (for example, the duration of a page visit).
</li>
<li><span class="font-bold">Website</span> refers to Duct Calc, accessible from [https://ductcalc.pro](https://ductcalc.pro).</li>
<li>
<span class="font-bold">You</span> means the individual accessing or using the Service, or the company, or other legal entity
on behalf of which such individual is accessing or using the Service, as applicable.
</li>
</ul>
<h2 class="text-2xl font-bold">Collecting and Using Your Personal Data</h2>
<h3 class="text-xl font-bold">Types of Data Collected</h3>
<h4 class="text-lg font-bold">Personal Data</h4>
<p>
While using Our Service, We may ask You to provide Us with certain personally identifiable
information that can be used to contact or identify You. Personally identifiable information may
include, but is not limited to:
</p>
<ul class="list-disc mx-6 space-y-2">
<li>Email address</li>
<li>First and last name</li>
<li>Phone number</li>
<li>Address, State, Province, ZIP/Postal Code, City</li>
</ul>
<h4 class="text-lg font-bold">Usage Data</h4>
<p>
Usage Data may include information such as Your Device's Internet Protocol address (e.g. IP
address), browser type, browser version, the pages of our Service that You visit, the time and date
of Your visit, the time spent on those pages, unique device identifiers and other diagnostic data.
When You access the Service by or through a mobile device, We may collect certain information
automatically, including, but not limited to, the type of mobile device You use, Your mobile
device's unique ID, the IP address of Your mobile device, Your mobile operating system, the type of
mobile Internet browser You use, unique device identifiers and other diagnostic data.
We may also collect information that Your browser sends whenever You visit Our Service or when You
access the Service by or through a mobile device.
</p>
<h4 class="text-lg font-bold">Tracking Technologies and Cookies</h4>
<p>
We use Cookies and similar tracking technologies to track the activity on Our Service and store
certain information. Tracking technologies We use include beacons, tags, and scripts to collect and
track information and to improve and analyze Our Service. The technologies We use may include:
</p>
<ul class="list-disc mx-6 space-y-2">
<li>
<span class="font-bold">Cookies or Browser Cookies.</span> A cookie is a small file placed on Your Device. You can instruct
Your browser to refuse all Cookies or to indicate when a Cookie is being sent. However, if You do
not accept Cookies, You may not be able to use some parts of our Service.
</li>
<li>
<span class="font-bold">Web Beacons</span> Certain sections of our Service and our emails may contain small electronic files
known as web beacons (also referred to as clear gifs, pixel tags, and single-pixel gifs) that
permit the Company, for example, to count users who have visited those pages or opened an email
and for other related website statistics (for example, recording the popularity of a certain
section and verifying system and server integrity).
</li>
</ul>
<p>
Cookies can be "Persistent" or "Session" Cookies. Persistent Cookies remain on Your personal
computer or mobile device when You go offline, while Session Cookies are deleted as soon as You
close Your web browser.
Where required by law, we use non-essential cookies (such as analytics, advertising, and remarketing
cookies) only with Your consent. You can withdraw or change Your consent at any time using Our
cookie preferences tool (if available) or through Your browser/device settings. Withdrawing consent
does not affect the lawfulness of processing based on consent before its withdrawal.
We use both Session and Persistent Cookies for the purposes set out below:
</p>
<ul class="list-disc mx-6 space-y-2">
<li>
<p class="font-bold">Necessary / Essential Cookies</p>
<p class="mx-6">
Type: Session Cookies
Administered by: Us
Purpose: These Cookies are essential to provide You with services available through the Website
and to enable You to use some of its features. They help to authenticate users and prevent
fraudulent use of user accounts. Without these Cookies, the services that You have asked for
cannot be provided, and We only use these Cookies to provide You with those services.
</p>
</li>
<li>
<p class="font-bold">Functionality Cookies</p>
<p class="mx-6">
Type: Persistent Cookies
Administered by: Us
Purpose: These Cookies allow Us to remember choices You make when You use the Website, such as
remembering your login details or language preference. The purpose of these Cookies is to
provide You with a more personal experience and to avoid You having to re-enter your preferences
every time You use the Website.
</p>
</li>
</ul>
<p>
For more information about the cookies we use and your choices regarding cookies, please visit our
Cookies Policy or the Cookies section of Our Privacy Policy.
</p>
<h3 class="text-2xl font-bold">Use of Your Personal Data</h3>
<p>The Company may use Personal Data for the following purposes:</p>
<ul class="list-disc mx-6 space-y-2">
<li><span class="font-bold">To provide and maintain our Service</span>, including to monitor the usage of our Service.</li>
<li>
<span class="font-bold">To manage Your Account:</span> to manage Your registration as a user of the Service. The Personal
Data You provide can give You access to different functionalities of the Service that are
available to You as a registered user.
</li>
<li>
<span class="font-bold">For the performance of a contract:</span> the development, compliance and undertaking of the purchase
contract for the products, items or services You have purchased or of any other contract with Us
through the Service.
</li>
<li>
<span class="font-bold">To contact You:</span> To contact You by email, telephone calls, SMS, or other equivalent forms of
electronic communication, such as a mobile application's push notifications regarding updates or
informative communications related to the functionalities, products or contracted services,
including the security updates, when necessary or reasonable for their implementation.
</li>
<li>
<span class="font-bold">To provide You</span> with news, special offers, and general information about other goods, services
and events which We offer that are similar to those that you have already purchased or inquired
about unless You have opted not to receive such information.
</li>
<li><span class="font-bold">To manage Your requests:</span> To attend and manage Your requests to Us.</li>
<li>
<span class="font-bold">For business transfers:</span> We may use Your Personal Data to evaluate or conduct a merger,
divestiture, restructuring, reorganization, dissolution, or other sale or transfer of some or all
of Our assets, whether as a going concern or as part of bankruptcy, liquidation, or similar
proceeding, in which Personal Data held by Us about our Service users is among the assets
transferred.
</li>
<li>
<span class="font-bold">For other purposes:</span> We may use Your information for other purposes, such as data analysis,
identifying usage trends, determining the effectiveness of our promotional campaigns and to
evaluate and improve our Service, products, services, marketing and your experience.
</li>
</ul>
<p>We may share Your Personal Data in the following situations:</p>
<ul class="list-disc mx-6 space-y-2">
<li>
<span class="font-bold">With Service Providers:</span> We may share Your Personal Data with Service Providers to monitor and
analyze the use of our Service, to contact You.
</li>
<li>
<span class="font-bold">For business transfers:</span> We may share or transfer Your Personal Data in connection with, or
during negotiations of, any merger, sale of Company assets, financing, or acquisition of all or a
portion of Our business to another company.
</li>
<li>
<span class="font-bold">With Affiliates:</span> We may share Your Personal Data with Our affiliates, in which case we will
require those affiliates to honor this Privacy Policy. Affiliates include Our parent company and
any other subsidiaries, joint venture partners or other companies that We control or that are
under common control with Us.
</li>
<li>
<span class="font-bold">With business partners:</span> We may share Your Personal Data with Our business partners to offer
You certain products, services or promotions.
</li>
<li>
<span class="font-bold">With other users:</span> If Our Service offers public areas, when You share Personal Data or
otherwise interact in the public areas with other users, such information may be viewed by all
users and may be publicly distributed outside.
</li>
<li><span class="font-bold">With Your consent:</span> We may disclose Your Personal Data for any other purpose with Your consent.</li>
</ul>
<h3 class="text-2xl font-bold">Retention of Your Personal Data</h3>
<p>
The Company will retain Your Personal Data only for as long as is necessary for the purposes set out
in this Privacy Policy. We will retain and use Your Personal Data to the extent necessary to comply
with our legal obligations (for example, if We are required to retain Your data to comply with
applicable laws), resolve disputes, and enforce our legal agreements and policies.
</p>
<p>
Where possible, We apply shorter retention periods and/or reduce identifiability by deleting,
aggregating, or anonymizing data. Unless otherwise stated, the retention periods below are maximum
periods ("up to") and We may delete or anonymize data sooner when it is no longer needed for the
relevant purpose. We apply different retention periods to different categories of Personal Data
based on the purpose of processing and legal obligations:
</p>
<ul class="list-disc mx-6 space-y-2">
<li>
Account Information
<ul class="list-disc mx-6 space-y-2">
<li>
User Accounts: retained for the duration of your account relationship plus up to 24 months
after account closure to handle any post-termination issues or resolve disputes.
</li>
</ul>
</li>
<li>
Customer Support Data
<ul class="list-disc mx-6 space-y-2">
<li>
Support tickets and correspondence: up to 24 months from the date of ticket closure to resolve
follow-up inquiries, track service quality, and defend against potential legal claims.
</li>
<li>Chat transcripts: up to 24 months for quality assurance and staff training purposes.</li>
</ul>
</li>
<li>
Usage Data
<ul class="list-disc mx-6 space-y-2">
<li>
Website analytics data (cookies, IP addresses, device identifiers): up to 24 months from the
date of collection, which allows us to analyze trends while respecting privacy principles.
</li>
<li>
Server logs (IP addresses, access times): up to 24 months for security monitoring and
troubleshooting purposes.
</li>
</ul>
</li>
</ul>
<p>
Usage Data is retained in accordance with the retention periods described above, and may be retained
longer only where necessary for security, fraud prevention, or legal compliance.
</p>
<p>We may retain Personal Data beyond the periods stated above for different reasons:</p>
<ul class="list-disc mx-6 space-y-2">
<li>
Legal obligation: We are required by law to retain specific data (e.g., financial records for tax
authorities).
</li>
<li>Legal claims: Data is necessary to establish, exercise, or defend legal claims.</li>
<li>Your explicit request: You ask Us to retain specific information.</li>
<li>Technical limitations: Data exists in backup systems that are scheduled for routine deletion.</li>
</ul>
<p>You may request information about how long We will retain Your Personal Data by contacting Us.</p>
<p>
When retention periods expire, We securely delete or anonymize Personal Data according to the
following procedures:
</p>
<ul class="list-disc mx-6 space-y-2">
<li>Deletion: Personal Data is removed from Our systems and no longer actively processed.</li>
<li>
Backup retention: Residual copies may remain in encrypted backups for a limited period consistent
with our backup retention schedule and are not restored except where necessary for security,
disaster recovery, or legal compliance.
</li>
<li>
Anonymization: In some cases, We convert Personal Data into anonymous statistical data that cannot
be linked back to You. This anonymized data may be retained indefinitely for research and
analytics.
</li>
</ul>
<h3 class="text-xl font-bold">Transfer of Your Personal Data</h3>
<p>
Your information, including Personal Data, is processed at the Company's operating offices and in
any other places where the parties involved in the processing are located. It means that this
information may be transferred to — and maintained on — computers located outside of Your state,
province, country or other governmental jurisdiction where the data protection laws may differ from
those from Your jurisdiction.
</p>
<p>
Where required by applicable law, We will ensure that international transfers of Your Personal Data
are subject to appropriate safeguards and supplementary measures where appropriate. The Company will
take all steps reasonably necessary to ensure that Your data is treated securely and in accordance
with this Privacy Policy and no transfer of Your Personal Data will take place to an organization or
a country unless there are adequate controls in place including the security of Your data and other
personal information.
</p>
<h3 class="text-xl font-bold">Delete Your Personal Data</h3>
<p>
You have the right to delete or request that We assist in deleting the Personal Data that We have
collected about You.
</p>
<p>
Our Service may give You the ability to delete certain information about You from within the
Service.
</p>
<p>
You may update, amend, or delete Your information at any time by signing in to Your Account, if you
have one, and visiting the account settings section that allows you to manage Your personal
information. You may also contact Us to request access to, correct, or delete any Personal Data that
You have provided to Us.
</p>
<p>
Please note, however, that We may need to retain certain information when we have a legal obligation
or lawful basis to do so.
</p>
<h3 class="text-xl font-bold">Disclosure of Your Personal Data</h3>
<h4 class="text-lg font-bold">Business Transactions</h4>
<p>
If the Company is involved in a merger, acquisition or asset sale, Your Personal Data may be
transferred. We will provide notice before Your Personal Data is transferred and becomes subject to
a different Privacy Policy.
</p>
<h4 class="text-lg font-bold">Law enforcement</h4>
<p>
Under certain circumstances, the Company may be required to disclose Your Personal Data if required
to do so by law or in response to valid requests by public authorities (e.g. a court or a government
agency).
</p>
<h4 class="text-lg font-bold">Other legal requirements</h4>
<p>
The Company may disclose Your Personal Data in the good faith belief that such action is necessary
to:
</p>
<ul class="list-disc mx-6 space-y-2">
<li>Comply with a legal obligation</li>
<li>Protect and defend the rights or property of the Company</li>
<li>Prevent or investigate possible wrongdoing in connection with the Service</li>
<li>Protect the personal safety of Users of the Service or the public</li>
<li>Protect against legal liability</li>
</ul>
<h3 class="text-xl font-bold">Security of Your Personal Data</h3>
<p>
The security of Your Personal Data is important to Us, but remember that no method of transmission
over the Internet, or method of electronic storage is 100% secure. While We strive to use
commercially reasonable means to protect Your Personal Data, We cannot guarantee its absolute
security.
</p>
<h2 class="text-2xl font-bold">Children's Privacy</h2>
<p>
Our Service does not address anyone under the age of 16. We do not knowingly collect personally
identifiable information from anyone under the age of 16. If You are a parent or guardian and You
are aware that Your child has provided Us with Personal Data, please contact Us. If We become aware
that We have collected Personal Data from anyone under the age of 16 without verification of
parental consent, We take steps to remove that information from Our servers.
</p>
<p>
If We need to rely on consent as a legal basis for processing Your information and Your country
requires consent from a parent, We may require Your parent's consent before We collect and use that
information.
</p>
<h2 class="text-2xl font-bold">Links to Other Websites</h2>
<p>
Our Service may contain links to other websites that are not operated by Us. If You click on a third
party link, You will be directed to that third party's site. We strongly advise You to review the
Privacy Policy of every site You visit.
</p>
<p>
We have no control over and assume no responsibility for the content, privacy policies or practices
of any third party sites or services.
</p>
<h2 class="text-2xl font-bold">Changes to this Privacy Policy</h2>
<p>
We may update Our Privacy Policy from time to time. We will notify You of any changes by posting the
new Privacy Policy on this page.
</p>
<p>
We will let You know via email and/or a prominent notice on Our Service, prior to the change
becoming effective and update the "Last updated" date at the top of this Privacy Policy.
</p>
<p>
You are advised to review this Privacy Policy periodically for any changes. Changes to this Privacy
Policy are effective when they are posted on this page.
</p>
<h2 class="text-2xl font-bold">Contact Us</h2>
<p>If you have any questions about this Privacy Policy, You can contact us:</p>
<ul class="list-disc mx-6 space-y-2">
<li><span>By email: </span><a href="mailto://support@ductcalc.pro" class="btn btn-link">support@ductcalc.pro</a></li>
</ul>
</div>
</main>
<div class="bottom-0 left-0 bg-error">
<footer class="footer footer-horizontal footer-center
bg-base-300 text-base-content p-4">
<aside class="grid-flow-row items-center">
<div class="flex mx-auto">
<a class="btn btn-ghost" href="mailto:support@ductcalc.pro"> <svg class="h-[1em] opacity-50" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<g
stroke-linejoin="round"
stroke-linecap="round"
stroke-width="2.5"
fill="none"
stroke="currentColor"
>
<rect width="20" height="16" x="2" y="4" rx="2"></rect>
<path d="m22 7-8.97 5.7a1.94 1.94 0 0 1-2.06 0L2 7"></path>
</g>
</svg><span>support@ductcalc.pro</span></a>
</div>
Openly licensed via CC-BY-NC-SA 4.0<a class="btn btn-ghost mx-auto" href="https://github.com/m-housh/swift-duct-calc/src/branch/main/LICENSE" target="_blank"></a>
<p class="">Copyright © 2026 - All rights reserved by Michael Housh</p>
</aside>
</footer>
</div>
</div>
</body>
</html>

View File

@@ -33,7 +33,10 @@
<main class="flex flex-col min-h-screen min-w-full grow mb-auto">
<dialog id="loginForm" class="modal modal-open">
<div class="modal-box">
<h1 class="text-2xl font-bold mb-6">Login</h1>
<div class="flex justify-between">
<h1 class="text-2xl font-bold mb-6">Login</h1>
Privacy Policy<a class="btn btn-link" href="/privacy-policy" target="_blank"></a>
</div>
<form method="post" class="space-y-4">
<div>
<label class="input validator w-full"> <svg class="h-[1em] opacity-50" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">