Capstone: Build and Test the Site

July 16, 2026 ยท View on GitHub

Build the complete website locally before making a public DNS or server change.

Step 1: Create the Project

mkdir -p capstone-site/assets capstone-site/notes
cd capstone-site

Create .gitignore:

.DS_Store
.env
*.log
notes/private-*

Initialize version control:

git init
git status

Step 2: Create the Home Page

Create index.html:

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="description" content="A short description of the project and its purpose.">
  <title>Example Project</title>
  <link rel="stylesheet" href="styles.css">
</head>
<body>
  <a class="skip-link" href="#content">Skip to content</a>
  <header class="site-header">
    <nav class="nav" aria-label="Primary navigation">
      <a class="brand" href="index.html">Example Project</a>
      <a href="about.html">About</a>
    </nav>
  </header>
  <main id="content" class="page">
    <p class="eyebrow">Open and useful</p>
    <h1>A clear statement of what the project does.</h1>
    <p class="lede">Explain who the project serves and why it exists in two short sentences.</p>
    <a class="button" href="about.html">Learn about the project</a>
  </main>
  <footer class="site-footer">
    <p>Contact: <a href="mailto:contact@example.dpdns.org">contact@example.dpdns.org</a></p>
  </footer>
</body>
</html>

Replace the fictional contact address only when a monitored mailbox exists and publishing it is intentional.

Step 3: Create the About Page

Create about.html:

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="description" content="Background, purpose, and contact information for Example Project.">
  <title>About | Example Project</title>
  <link rel="stylesheet" href="styles.css">
</head>
<body>
  <a class="skip-link" href="#content">Skip to content</a>
  <header class="site-header">
    <nav class="nav" aria-label="Primary navigation">
      <a class="brand" href="index.html">Example Project</a>
      <a aria-current="page" href="about.html">About</a>
    </nav>
  </header>
  <main id="content" class="page prose">
    <h1>About the project</h1>
    <p>Describe the problem that led to the project.</p>
    <h2>What we provide</h2>
    <p>Describe the useful information or service available here.</p>
    <h2>Contact</h2>
    <p>Explain how a visitor can reach the responsible team.</p>
  </main>
  <footer class="site-footer">
    <p><a href="index.html">Return home</a></p>
  </footer>
</body>
</html>

Step 4: Create the Stylesheet

Create styles.css:

*,
*::before,
*::after {
  box-sizing: border-box;
}

:root {
  color-scheme: light;
  font-family: system-ui, sans-serif;
  line-height: 1.6;
  background: #f8fafc;
  color: #0f172a;
}

body {
  min-height: 100vh;
  margin: 0;
}

a {
  color: #075985;
}

a:focus-visible {
  outline: 3px solid #0ea5e9;
  outline-offset: 3px;
}

.skip-link {
  position: absolute;
  left: 1rem;
  top: -5rem;
  padding: 0.75rem 1rem;
  background: #ffffff;
}

.skip-link:focus {
  top: 1rem;
}

.site-header,
.site-footer {
  border-block: 1px solid #cbd5e1;
  background: #ffffff;
}

.nav,
.page,
.site-footer p {
  width: min(68rem, calc(100% - 2rem));
  margin-inline: auto;
}

.nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 4rem;
}

.brand {
  font-weight: 750;
  text-decoration: none;
}

.page {
  padding-block: clamp(4rem, 10vw, 8rem);
}

.page h1 {
  max-width: 18ch;
  font-size: clamp(2.25rem, 6vw, 4.75rem);
  line-height: 1.05;
}

.eyebrow {
  color: #0369a1;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.lede,
.prose {
  max-width: 44rem;
}

.button {
  display: inline-block;
  margin-top: 1rem;
  padding: 0.8rem 1rem;
  border-radius: 0.5rem;
  background: #075985;
  color: #ffffff;
  font-weight: 700;
  text-decoration: none;
}

.site-footer {
  padding-block: 1rem;
}

@media (prefers-reduced-motion: no-preference) {
  a {
    transition: color 150ms ease, background-color 150ms ease;
  }
}

Step 5: Run the Local Server

python3 -m http.server 8000 --bind 127.0.0.1

Open http://127.0.0.1:8000/.

Step 6: Functional Tests

In another terminal:

curl -I http://127.0.0.1:8000/
curl -I http://127.0.0.1:8000/about.html
curl -I http://127.0.0.1:8000/styles.css

Expected:

  • Both pages return 200.
  • The stylesheet returns 200 with a CSS content type.
  • Home links to About.
  • About links to Home.

Step 7: Accessibility Tests

  • Navigate with Tab and Enter.
  • Confirm the skip link appears on focus.
  • Confirm focus remains visible.
  • Zoom to 200 percent.
  • Test a narrow viewport.
  • Confirm heading order.
  • Confirm every link describes its destination.

Step 8: Content and Privacy Review

Search the project:

rg -n -i 'password|token|secret|api[_-]?key|192\.168\.' .

Review every match. Confirm that the public contact data is intentional and no private notes are inside the site directory.

Step 9: Save the Baseline

git add index.html about.html styles.css .gitignore
git diff --cached
git commit -m "Create capstone static site"

Only commit after reviewing the staged content.

Gate Before Public Work

Do not continue until all local tests pass and the source can rebuild the site on another machine.

Continue to Register, Deploy, and Connect.