Add Dockerfile, nginx config, docker-compose; remove stale files; update CLAUDE.md

This commit is contained in:
Amit Rana 2026-04-15 11:12:44 +05:30
parent ddbfef1692
commit d2e4063cf8
9 changed files with 156 additions and 362 deletions

142
CLAUDE.md
View File

@ -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
View 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;"]

View File

@ -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
View 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
View 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;
}
}

View File

@ -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;
}

View File

@ -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>
);
}

View File

@ -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.

View File

@ -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;">
&lt;script src="https://quantumtaskai.com/header.js"&gt;&lt;/script&gt;</pre>
<p>That's it. No extra HTML, no CSS imports, no dependencies.</p>
</main>
</body>
</html>