mirror of
https://github.com/thecyberlearn/quantum-website-2026.git
synced 2026-08-18 07:43:20 +00:00
Add Dockerfile, nginx config, docker-compose; remove stale files; update CLAUDE.md
This commit is contained in:
parent
ddbfef1692
commit
d2e4063cf8
142
CLAUDE.md
142
CLAUDE.md
@ -1,107 +1,89 @@
|
||||
# CLAUDE.md
|
||||
|
||||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||||
This file provides guidance to Claude Code when working with code in this repository.
|
||||
|
||||
## Project Overview
|
||||
|
||||
This is a static marketing website for Quantum Tasks AI, built with HTML/CSS/JavaScript and deployed using Docker/nginx. The site is containerized for deployment via Dokploy with Traefik reverse proxy handling SSL and routing.
|
||||
Static marketing website for Quantum Tasks AI, served via nginx in Docker and deployed via Dokploy with Traefik for SSL and routing.
|
||||
|
||||
## Architecture
|
||||
## File Structure
|
||||
|
||||
### Core Structure
|
||||
- `index.html` - Main homepage with hero section, company profile, services overview, and integrated contact form
|
||||
- `digital-branding.html` - AI Digital Branding services page with SOSTAC+RACE framework
|
||||
- `css/style.css` - Consolidated stylesheet with responsive design and CSS custom properties
|
||||
- `js/script.js` - Interactive functionality for forms, navigation, and animations
|
||||
|
||||
### Deployment Architecture
|
||||
- **Static Site**: Served via nginx in Docker container
|
||||
- **Container**: Alpine-based nginx image with optimized caching headers
|
||||
- **Orchestration**: Docker Compose with Traefik labels for automatic SSL/routing
|
||||
- **Platform**: Dokploy deployment with domains `quantumtaskai.com` and `www.quantumtaskai.com`
|
||||
|
||||
## Development Commands
|
||||
|
||||
This is a static website with no build process - files are served directly by nginx.
|
||||
|
||||
### Local Development
|
||||
```bash
|
||||
# Serve locally with any static server
|
||||
python -m http.server 8000
|
||||
# or
|
||||
npx serve .
|
||||
```
|
||||
index.html — Homepage (dark navy hero, services, founders, contact)
|
||||
digital-branding.html — AI Digital Branding services page (SOSTAC+RACE)
|
||||
privacy.html — Privacy Policy
|
||||
terms.html — Terms of Service
|
||||
404.html — Custom 404 page
|
||||
header.js — Shared self-injecting header (loaded cross-domain)
|
||||
robots.txt — Search engine crawl instructions
|
||||
sitemap.xml — XML sitemap (4 pages)
|
||||
Dockerfile — nginx:alpine image
|
||||
docker-compose.yml — Production config with Traefik labels
|
||||
nginx.conf — nginx routing, caching headers, security headers, 404
|
||||
img/ — logo.png, favicon.ico, favicon-*.png, apple-touch-icon.png, og-image.png
|
||||
```
|
||||
|
||||
### Docker Development
|
||||
## Shared Header
|
||||
|
||||
`header.js` is a self-injecting IIFE loaded by all Quantum Tasks AI apps:
|
||||
- Static site: `<script src="/header.js">`
|
||||
- Blog (blog.quantumtaskai.com): `<script src="https://quantumtaskai.com/header.js">`
|
||||
- Auditor (audit.quantumtaskai.com): `<script src="https://quantumtaskai.com/header.js">`
|
||||
|
||||
To update nav links or colors across all apps — edit `header.js` only.
|
||||
|
||||
## Local Development
|
||||
|
||||
```bash
|
||||
# Build and run locally
|
||||
# Simple static server
|
||||
python -m http.server 8000
|
||||
|
||||
# Docker (matches production)
|
||||
docker build -t quantumtaskai-website .
|
||||
docker run -p 8080:80 quantumtaskai-website
|
||||
|
||||
# Using docker-compose
|
||||
docker-compose up --build
|
||||
```
|
||||
|
||||
### Deployment
|
||||
## Deployment
|
||||
|
||||
Deployed via Dokploy. Push to `main` branch triggers redeployment.
|
||||
|
||||
```bash
|
||||
# Deploy to Dokploy (production)
|
||||
# Uses dokploy.json configuration for automatic deployment
|
||||
git push origin main # Triggers deployment if configured
|
||||
|
||||
# Test deployment locally
|
||||
docker-compose -f docker-compose.test.yml up --build
|
||||
git push origin main
|
||||
```
|
||||
|
||||
## Key Integration Points
|
||||
Domains: `quantumtaskai.com` and `www.quantumtaskai.com` (www redirects to non-www).
|
||||
|
||||
### External Links
|
||||
- AI Marketplace: Links point to `https://aiagent.quantumtaskai.com/agents/` (Django app)
|
||||
- Authentication: Separate login/register buttons link to Django auth endpoints
|
||||
## Domain Strategy
|
||||
|
||||
### Contact Form
|
||||
- Integrated into homepage `#contact` section
|
||||
- Client-side validation implemented in `js/script.js`
|
||||
- Ready for Netlify Forms, Formspree, or Django backend integration
|
||||
- Demo success message shows on submission
|
||||
| Domain | What it is |
|
||||
|---|---|
|
||||
| `quantumtaskai.com` | This static site |
|
||||
| `audit.quantumtaskai.com` | Site Auditor (separate Django app) |
|
||||
| `blog.quantumtaskai.com` | Blog (separate Django app) |
|
||||
|
||||
### Domain Strategy
|
||||
- `quantumtaskai.com` - Static marketing site (this repository)
|
||||
- `aiagent.quantumtaskai.com` - Django AI marketplace (separate application)
|
||||
- `www.quantumtaskai.com` - Redirects to main domain
|
||||
## Key URLs
|
||||
|
||||
## Configuration Files
|
||||
- Contact form: uses JotForm `https://form.jotform.com/252121444918050`
|
||||
- Email: `abhay@quantumtaskai.com`
|
||||
- Address: Meydan Grandstand, 6th floor, Dubai, UAE
|
||||
|
||||
### Docker Configuration
|
||||
- `Dockerfile` - nginx Alpine image with security headers and caching
|
||||
- `docker-compose.yml` - Production configuration with Traefik labels
|
||||
- `docker-compose.test.yml` - Test configuration without domain dependencies
|
||||
## Design System
|
||||
|
||||
### Deployment Configuration
|
||||
- `dokploy.json` - Dokploy platform configuration with domains, SSL, monitoring
|
||||
- `dokploy.test.json` - Test environment configuration
|
||||
- `DEPLOYMENT.md` - Comprehensive deployment guide for multiple platforms
|
||||
Both `index.html` and `digital-branding.html` use an embedded `<style>` block with shared CSS variables:
|
||||
|
||||
## Assets Requirements
|
||||
```css
|
||||
--navy: #0a0f1e /* hero backgrounds */
|
||||
--indigo: #6366f1 /* primary accent */
|
||||
--violet: #a855f7 /* secondary accent */
|
||||
--orange: #f97316 /* CTA buttons */
|
||||
```
|
||||
|
||||
The `img/` directory should contain:
|
||||
- `logo.png` - Company logo (200x60px recommended)
|
||||
- `favicon.ico` - Website favicon (32x32px)
|
||||
- `og-image.png` - Social media preview (1200x630px)
|
||||
- Additional favicon sizes for mobile devices
|
||||
No external CSS file — all styles are embedded per-page for simplicity.
|
||||
|
||||
## Performance Features
|
||||
## nginx Features (nginx.conf)
|
||||
|
||||
- Static file caching (1 year for assets, 1 hour for HTML)
|
||||
- Security headers (X-Frame-Options, X-Content-Type-Options, X-XSS-Protection)
|
||||
- Responsive images and mobile-first CSS
|
||||
- Optimized font loading with preload
|
||||
- Minified and consolidated CSS/JS
|
||||
|
||||
## SEO & Marketing
|
||||
|
||||
- Structured data markup for business information
|
||||
- OpenGraph meta tags for social sharing
|
||||
- Proper heading hierarchy and semantic HTML
|
||||
- Mobile-responsive design
|
||||
- Contact form integration for lead capture
|
||||
- Service pages optimized for AI/cybersecurity keywords
|
||||
- HTML cached 1 hour, assets cached 1 year
|
||||
- Security headers: X-Frame-Options, X-Content-Type-Options, X-XSS-Protection
|
||||
- Gzip compression enabled
|
||||
- Custom 404 page (`/404.html`)
|
||||
- www → non-www redirect
|
||||
|
||||
14
Dockerfile
Normal file
14
Dockerfile
Normal file
@ -0,0 +1,14 @@
|
||||
FROM nginx:alpine
|
||||
|
||||
# Remove default nginx config
|
||||
RUN rm /etc/nginx/conf.d/default.conf
|
||||
|
||||
# Copy site files
|
||||
COPY . /usr/share/nginx/html
|
||||
|
||||
# Copy nginx config
|
||||
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
@ -1,25 +0,0 @@
|
||||
{% load static %}
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{% block title %}YourSite{% endblock %}</title>
|
||||
{% block extra_head %}{% endblock %}
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!--
|
||||
Shared Header
|
||||
Update the src URL below to point to your live static site.
|
||||
To bust cache after updating header.js, append ?v=2 to the URL.
|
||||
-->
|
||||
<script src="https://quantumtaskai.com/header.js"></script>
|
||||
|
||||
<main>
|
||||
{% block content %}{% endblock %}
|
||||
</main>
|
||||
|
||||
{% block extra_scripts %}{% endblock %}
|
||||
</body>
|
||||
</html>
|
||||
23
docker-compose.yml
Normal file
23
docker-compose.yml
Normal file
@ -0,0 +1,23 @@
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
web:
|
||||
build: .
|
||||
restart: unless-stopped
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.quantumweb.rule=Host(`quantumtaskai.com`) || Host(`www.quantumtaskai.com`)"
|
||||
- "traefik.http.routers.quantumweb.entrypoints=websecure"
|
||||
- "traefik.http.routers.quantumweb.tls.certresolver=letsencrypt"
|
||||
- "traefik.http.services.quantumweb.loadbalancer.server.port=80"
|
||||
# www → non-www redirect
|
||||
- "traefik.http.middlewares.www-redirect.redirectregex.regex=^https://www\\.quantumtaskai\\.com/(.*)"
|
||||
- "traefik.http.middlewares.www-redirect.redirectregex.replacement=https://quantumtaskai.com/$${1}"
|
||||
- "traefik.http.middlewares.www-redirect.redirectregex.permanent=true"
|
||||
- "traefik.http.routers.quantumweb.middlewares=www-redirect"
|
||||
networks:
|
||||
- traefik-public
|
||||
|
||||
networks:
|
||||
traefik-public:
|
||||
external: true
|
||||
57
nginx.conf
Normal file
57
nginx.conf
Normal file
@ -0,0 +1,57 @@
|
||||
server {
|
||||
listen 80;
|
||||
server_name quantumtaskai.com www.quantumtaskai.com;
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
charset utf-8;
|
||||
|
||||
# ── Security headers ─────────────────────────────────────────
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
||||
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
|
||||
|
||||
# ── Gzip compression ─────────────────────────────────────────
|
||||
gzip on;
|
||||
gzip_types text/plain text/css text/javascript application/javascript
|
||||
application/json image/svg+xml;
|
||||
gzip_min_length 1024;
|
||||
|
||||
# ── Caching: HTML (1 hour) ───────────────────────────────────
|
||||
location ~* \.html$ {
|
||||
add_header Cache-Control "public, max-age=3600, must-revalidate";
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
try_files $uri $uri/ =404;
|
||||
}
|
||||
|
||||
# ── Caching: Static assets (1 year) ─────────────────────────
|
||||
location ~* \.(ico|png|jpg|jpeg|webp|gif|svg|woff|woff2|ttf|js|css)$ {
|
||||
add_header Cache-Control "public, max-age=31536000, immutable";
|
||||
access_log off;
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
# ── Caching: sitemap and robots (1 day) ─────────────────────
|
||||
location ~* \.(xml|txt)$ {
|
||||
add_header Cache-Control "public, max-age=86400";
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
# ── www → non-www redirect ───────────────────────────────────
|
||||
if ($host = "www.quantumtaskai.com") {
|
||||
return 301 https://quantumtaskai.com$request_uri;
|
||||
}
|
||||
|
||||
# ── Main routing ─────────────────────────────────────────────
|
||||
location / {
|
||||
try_files $uri $uri/ $uri.html =404;
|
||||
}
|
||||
|
||||
# ── 404 page ─────────────────────────────────────────────────
|
||||
error_page 404 /404.html;
|
||||
location = /404.html {
|
||||
internal;
|
||||
}
|
||||
}
|
||||
@ -1,45 +0,0 @@
|
||||
import { useEffect } from 'react';
|
||||
|
||||
/**
|
||||
* SharedHeader
|
||||
*
|
||||
* Dynamically loads the shared header script from your static site.
|
||||
* Renders nothing itself — the script injects the header into <body>.
|
||||
*
|
||||
* Usage:
|
||||
* import SharedHeader from '@/components/SharedHeader';
|
||||
* // Place it once in your root layout:
|
||||
* <SharedHeader />
|
||||
*
|
||||
* To bust cache after updating header.js, change the version param:
|
||||
* const HEADER_URL = 'https://quantumtaskai.com/header.js?v=2';
|
||||
*/
|
||||
|
||||
const HEADER_URL = 'https://quantumtaskai.com/header.js';
|
||||
|
||||
export default function SharedHeader() {
|
||||
useEffect(() => {
|
||||
// Avoid loading twice (e.g. StrictMode double-invoke)
|
||||
if (document.getElementById('sh-header')) return;
|
||||
if (document.querySelector(`script[src="${HEADER_URL}"]`)) return;
|
||||
|
||||
const script = document.createElement('script');
|
||||
script.src = HEADER_URL;
|
||||
script.async = true;
|
||||
document.body.appendChild(script);
|
||||
|
||||
return () => {
|
||||
// Clean up on unmount
|
||||
const injectedScript = document.querySelector(`script[src="${HEADER_URL}"]`);
|
||||
if (injectedScript) injectedScript.remove();
|
||||
|
||||
const injectedHeader = document.getElementById('sh-header');
|
||||
if (injectedHeader) injectedHeader.remove();
|
||||
|
||||
const injectedStyles = document.getElementById('sh-styles');
|
||||
if (injectedStyles) injectedStyles.remove();
|
||||
};
|
||||
}, []);
|
||||
|
||||
return null;
|
||||
}
|
||||
@ -1,25 +0,0 @@
|
||||
import SharedHeader from '@/components/SharedHeader';
|
||||
|
||||
/**
|
||||
* Root layout for Next.js (works for both app/ and pages/ router).
|
||||
*
|
||||
* app/ router: use this as app/layout.jsx
|
||||
* pages/ router: use this as pages/_app.jsx, wrapping <Component {...pageProps} />
|
||||
*
|
||||
* The padding-top on <main> prevents page content from being hidden
|
||||
* behind the sticky header (64px desktop / 56px mobile).
|
||||
*/
|
||||
export default function RootLayout({ children }) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body>
|
||||
{/* Injects the shared header into <body> via header.js */}
|
||||
<SharedHeader />
|
||||
|
||||
<main style={{ paddingTop: '64px' }}>
|
||||
{children}
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
@ -1,158 +0,0 @@
|
||||
# Shared Header System
|
||||
|
||||
One header file. Three apps. Zero duplication.
|
||||
|
||||
## How It Works
|
||||
|
||||
```
|
||||
header.js (hosted on your main static site)
|
||||
│
|
||||
├── Static HTML site → <script src="/header.js">
|
||||
├── Django app → <script src="https://yoursite.com/header.js">
|
||||
└── React / Next.js app → <SharedHeader /> component
|
||||
```
|
||||
|
||||
When `header.js` loads in any app, it:
|
||||
1. Injects a `<style>` block into `<head>`
|
||||
2. Injects the header HTML at the top of `<body>`
|
||||
3. Attaches hamburger toggle logic for mobile
|
||||
4. Highlights the active nav link based on the current URL
|
||||
|
||||
---
|
||||
|
||||
## Step 1 — Host header.js on Your Static Site
|
||||
|
||||
Copy `header.js` to the root of your static site so it's accessible at:
|
||||
```
|
||||
https://yoursite.com/header.js
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Step 2 — Static HTML Setup
|
||||
|
||||
Add one line anywhere in `<body>`:
|
||||
|
||||
```html
|
||||
<script src="https://yoursite.com/header.js"></script>
|
||||
```
|
||||
|
||||
See `static-site-example.html` for a full working example.
|
||||
|
||||
---
|
||||
|
||||
## Step 3 — Django Setup
|
||||
|
||||
In your `base.html` template, add after `{% load static %}`:
|
||||
|
||||
```html
|
||||
<script src="https://yoursite.com/header.js"></script>
|
||||
```
|
||||
|
||||
All templates that extend `base.html` automatically get the header.
|
||||
See `django-base.html` for a full base template example.
|
||||
|
||||
---
|
||||
|
||||
## Step 4 — React / Next.js Setup
|
||||
|
||||
**1. Copy the component** to your project:
|
||||
```
|
||||
src/components/SharedHeader.jsx (from react-SharedHeader.jsx)
|
||||
```
|
||||
|
||||
**2. Add it to your root layout** (from `react-layout-example.jsx`):
|
||||
```jsx
|
||||
import SharedHeader from '@/components/SharedHeader';
|
||||
|
||||
export default function RootLayout({ children }) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body>
|
||||
<SharedHeader />
|
||||
<main style={{ paddingTop: '64px' }}>
|
||||
{children}
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Updating Nav Links
|
||||
|
||||
Edit the `NAV_LINKS` array at the top of `header.js`:
|
||||
|
||||
```js
|
||||
var NAV_LINKS = [
|
||||
{ label: 'Home', url: 'https://yoursite.com' },
|
||||
{ label: 'About', url: 'https://yoursite.com/about' },
|
||||
// add or remove items here
|
||||
];
|
||||
```
|
||||
|
||||
All connected apps reflect the change on next page load. No deploys needed for Django or React — they load the script remotely.
|
||||
|
||||
---
|
||||
|
||||
## Updating Colors
|
||||
|
||||
Edit the CSS variables near the top of `header.js`:
|
||||
|
||||
```css
|
||||
:root {
|
||||
--sh-bg: #0a0e1a; /* background */
|
||||
--sh-accent: #3b82f6; /* accent / active color */
|
||||
--sh-text: #ffffff; /* nav link text */
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Adding a New App
|
||||
|
||||
Any app — PHP, Ruby, Vue, plain HTML — needs exactly one line:
|
||||
|
||||
```html
|
||||
<script src="https://yoursite.com/header.js"></script>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Cache Busting After Updates
|
||||
|
||||
When you update `header.js`, browsers may serve the old cached version.
|
||||
Append a version query param to force a fresh fetch:
|
||||
|
||||
```html
|
||||
<!-- bump ?v= each time you update header.js -->
|
||||
<script src="https://yoursite.com/header.js?v=2"></script>
|
||||
```
|
||||
|
||||
Update this in all three places (static HTML, Django base template, `SharedHeader.jsx`).
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**Header not showing?**
|
||||
- Open browser DevTools → Network tab → check if `header.js` loaded (200 status).
|
||||
- Check the console for errors.
|
||||
|
||||
**CORS error in Django or React?**
|
||||
- Your static site's server must allow cross-origin requests for JS files.
|
||||
- In nginx, add to your server block:
|
||||
```nginx
|
||||
add_header Access-Control-Allow-Origin "*";
|
||||
```
|
||||
|
||||
**Content flashes before header appears?**
|
||||
- Add `min-height: 64px` to a placeholder div before the script tag, or load the script in `<head>` with `defer`.
|
||||
|
||||
**z-index conflict (header appears behind other elements)?**
|
||||
- The header uses `z-index: 99999`. If something still overlaps it, check for `z-index` or `transform` on a parent element (transforms create new stacking contexts).
|
||||
|
||||
**Double header on React hot reload?**
|
||||
- `header.js` checks `if (document.getElementById('sh-header')) return;` — this prevents double injection automatically.
|
||||
@ -1,29 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Page Title - YourSite</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- ─────────────────────────────────────────────────────────────
|
||||
Shared Header — one line, that's it.
|
||||
For same-domain use: <script src="/header.js"></script>
|
||||
For cross-domain use: <script src="https://quantumtaskai.com/header.js"></script>
|
||||
To bust cache after update: <script src="https://quantumtaskai.com/header.js?v=2"></script>
|
||||
──────────────────────────────────────────────────────────────── -->
|
||||
<script src="/header.js"></script>
|
||||
|
||||
<!-- Your page content below -->
|
||||
<main style="max-width:800px; margin:60px auto; padding:0 24px; font-family:sans-serif;">
|
||||
<h1>Welcome to YourSite</h1>
|
||||
<p>The header above is injected automatically by <code>header.js</code>.</p>
|
||||
<p>To use on any page, add one script tag:</p>
|
||||
<pre style="background:#f4f4f4; padding:16px; border-radius:8px;">
|
||||
<script src="https://quantumtaskai.com/header.js"></script></pre>
|
||||
<p>That's it. No extra HTML, no CSS imports, no dependencies.</p>
|
||||
</main>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Reference in New Issue
Block a user