c561a18277
The www subdomain still serves the old site, so canonical and hreflang URLs now use aigrowthtechnologies.com (overridable with SITE_URL). The sitemap also lists lastmod and changefreq.
91 lines
3.2 KiB
Markdown
91 lines
3.2 KiB
Markdown
# AI Growth Technologies — website
|
|
|
|
Next.js 16 (App Router) site for aigrowthtechnologies.com.
|
|
|
|
## Local development
|
|
|
|
```bash
|
|
npm ci
|
|
npm run dev # http://localhost:3000
|
|
```
|
|
|
|
## Environment variables
|
|
|
|
Copy `.env.example` to `.env.production` (or `.env.local` for development) and fill it in.
|
|
|
|
| Variable | Required | Purpose |
|
|
|---|---|---|
|
|
| `RESEND_API_KEY` | yes | Resend key with sending access to `aigrowthtechnologies.com`. Without it the contact form shows an error. |
|
|
| `CONTACT_FROM` | yes | Sender, on the domain verified in Resend: `AI Growth Website <hello@aigrowthtechnologies.com>` |
|
|
| `CONTACT_TO` | no | Inbox that receives enquiries; separate several with commas. Defaults to `rey@aigrowth360.io`. |
|
|
| `SITE_URL` | no | Public address used for canonical links, hreflang, `sitemap.xml` and `robots.txt`. Defaults to `https://aigrowthtechnologies.com`. |
|
|
| `CAPTCHA_SECRET` | no | Signs the contact form's "I'm not a robot" challenges (a self-hosted proof of work, no third-party account). Without it a random secret is used per process, which only matters across restarts. |
|
|
|
|
## Deploying to a VPS
|
|
|
|
Requirements: Node.js 20.9 or newer (22 LTS recommended), npm, nginx, and a process manager such as pm2.
|
|
|
|
```bash
|
|
git clone https://github.com/AlejandroVeras/aigrowth-website.git
|
|
cd aigrowth-website
|
|
cp .env.example .env.production # then edit it
|
|
npm ci
|
|
npm run build
|
|
pm2 start npm --name aigrowth-website -- start -- -p 3000
|
|
pm2 save && pm2 startup # restart on reboot
|
|
```
|
|
|
|
To update later:
|
|
|
|
```bash
|
|
git pull && npm ci && npm run build && pm2 restart aigrowth-website
|
|
```
|
|
|
|
### nginx
|
|
|
|
Put nginx in front of the Node server and turn off buffering so streamed pages arrive progressively:
|
|
|
|
```nginx
|
|
server {
|
|
server_name aigrowthtechnologies.com www.aigrowthtechnologies.com;
|
|
|
|
location / {
|
|
proxy_pass http://127.0.0.1:3000;
|
|
proxy_http_version 1.1;
|
|
proxy_set_header Host $host;
|
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
proxy_set_header X-Forwarded-Proto $scheme;
|
|
proxy_set_header Upgrade $http_upgrade;
|
|
proxy_set_header Connection "upgrade";
|
|
proxy_buffering off;
|
|
}
|
|
}
|
|
```
|
|
|
|
Then issue HTTPS with `sudo certbot --nginx -d aigrowthtechnologies.com -d www.aigrowthtechnologies.com`.
|
|
|
|
### DNS
|
|
|
|
At Hostinger, point the `A` records for `@` and `www` to the VPS IP. Leave the MX records (Titan email) and the Resend
|
|
records (`send`, `resend._domainkey`) as they are.
|
|
|
|
## Languages
|
|
|
|
The site is served in English (`/`), Spanish (`/es`) and Arabic (`/ar`, right to left). `src/proxy.ts` maps the
|
|
unprefixed English URLs onto `app/[lang]`. Interface strings live in `src/i18n/ui/`, homepage copy in
|
|
`src/content/home/`, and content pages in `src/content/pages/<locale>/`.
|
|
|
|
## Content
|
|
|
|
Inner pages are generated from the Word copy decks:
|
|
|
|
```bash
|
|
python3 -E scripts/convert-docs.py "<folder with the .docx files>"
|
|
```
|
|
|
|
This rewrites `src/content/pages/en/*.json`. The homepage (`src/app/[lang]/page.tsx`) is written by hand.
|
|
|
|
Translations keep the English structure. `python3 -E scripts/i18n.py extract <dir>` writes the strings to translate,
|
|
`python3 -E scripts/i18n.py apply <es|ar> <dir>` writes the translated pages, and
|
|
`python3 -E scripts/i18n.py index` regenerates `src/content/pages/index.ts`.
|