Update SOPs: consolidate index, clean client data, set Imagen as default
- README: rewrite index to reflect actual files (STACK/CONTENT/OPTIMIZATION); remove 15 dead links to old numbered SOPs; add subdirectory table; update image gen to Google Imagen as default - STACK: fix wp-divi-pipeline script paths; genericize vibrantyou/domain examples; strip pre-existing em dashes throughout - CONTENT: update image generation default to Google Imagen API with allotted quota - image-gen-workflow: remove client-specific cobhamtech data; generalize brand palette step; update date - wp-divi-pipeline-to-am-stack: remove vibrantyou.yoga client data block; fix Related SOPs links to current files
This commit is contained in:
+1
-1
@@ -82,7 +82,7 @@ Hero images: unique per page, named hero-{page-slug}.webp.
|
|||||||
|
|
||||||
## Image Generation
|
## Image Generation
|
||||||
|
|
||||||
Preferred source: local ComfyUI (FLUX.1 Schnell) or Google Imagen API.
|
Default source: Google Imagen API (imagen-4.0-generate-001) with allotted quota per project.
|
||||||
|
|
||||||
Every generated image passes a vision validation check for people/faces before being saved.
|
Every generated image passes a vision validation check for people/faces before being saved.
|
||||||
|
|
||||||
|
|||||||
@@ -1,95 +1,81 @@
|
|||||||
# Arising Media — Web Design SOPs
|
# Arising Media Web Design SOPs
|
||||||
|
|
||||||
Standard operating procedures for building, migrating, and deploying websites
|
Standard operating procedures for building, migrating, and deploying websites the Arising Media way. Reference `stack-selector.json` FIRST to pick the correct stack before touching any other SOP.
|
||||||
the Arising Media way. Reference `stack-selector.json` FIRST to pick the correct
|
|
||||||
stack before touching any other SOP.
|
|
||||||
|
|
||||||
## Stack selector (read this first)
|
## Stack selector (read this first)
|
||||||
|
|
||||||
`stack-selector.json` — machine-readable + human-readable decision guide.
|
`stack-selector.json`: machine-readable + human-readable decision guide. Covers all three stacks, approved colors, section types, DB guidance, hot-copy commands.
|
||||||
Covers all three stacks, approved colors, section types, DB guidance, hot-copy commands.
|
|
||||||
|
|
||||||
## Two primary stacks (2026-05-21 standard)
|
## Primary SOP files
|
||||||
|
|
||||||
### Stack A — PHP Router + SQLite (50+ page sites)
|
| File | Covers |
|
||||||
**Reference: `arisingmedia.us`** — 10,000+ pages, single router, SQLite content DB.
|
|------|--------|
|
||||||
Edit one template → all pages in that class update instantly. No find-and-replace.
|
| `STACK.md` | Architecture, project structure, build pipeline, WP migration, Docker/nginx deployment, cPanel deployment, DNS/email, form handling, PHP app stack |
|
||||||
Architecture diagram: `arisingmedia.us/.planning/RENDER_ARCHITECTURE.html`
|
| `CONTENT.md` | Writing standards, tone by sector, healthcare credential rules, copy structure, image standards, image generation, prompt engineering |
|
||||||
|
| `OPTIMIZATION.md` | Mobile responsive, breakpoints, SEO meta, schema.org, robots.txt, sitemap, testing/verification, performance standards |
|
||||||
|
|
||||||
|
## Three stacks (2026-05-21 standard)
|
||||||
|
|
||||||
|
### Stack A: PHP Router + SQLite (50+ page sites)
|
||||||
|
Reference: `arisingmedia.us`. 10,000+ pages, single router, SQLite content DB.
|
||||||
|
Edit one template and all pages in that class update instantly.
|
||||||
Build standard: `arisingmedia.us/.planning/WEBSITE_BUILD_STANDARD.md`
|
Build standard: `arisingmedia.us/.planning/WEBSITE_BUILD_STANDARD.md`
|
||||||
SOP: `15-php-router-sqlite-standard.md`
|
Stack A uses raw docker commands only. No docker compose.
|
||||||
|
|
||||||
### Stack B — Static HTML (fewer than 50 pages)
|
### Stack B: Static HTML (fewer than 50 pages)
|
||||||
**Reference: `lahrcarpetcleaning.com`** — universal Docker + cPanel deployment.
|
Reference: `lahrcarpetcleaning.com`. Universal Docker + cPanel deployment.
|
||||||
Every page is an HTML file on disk. Simple, portable, no server-side requirements.
|
Every page is an HTML file on disk. Simple, portable, no server-side requirements.
|
||||||
SOP: `01-project-structure.md`, `03-build-pipeline.md`, `08-deployment-docker.md`
|
|
||||||
|
|
||||||
### Stack C — PHP App (file processing, auth, payments)
|
### Stack C: PHP App (file processing, auth, payments)
|
||||||
**Reference: `quickconvert.us`**
|
Reference: `quickconvert.us`
|
||||||
SOP: `14-php-app-stack.md`
|
See STACK.md PHP App Stack section.
|
||||||
|
|
||||||
## Index
|
## Subdirectories
|
||||||
|
|
||||||
1. [00-stack-philosophy.md](00-stack-philosophy.md) — Why static HTML + vanilla JS + Python tooling, what we never use
|
| Directory | Purpose |
|
||||||
2. [01-project-structure.md](01-project-structure.md) — Folder layout: flat HTML (Docker) vs directory-style (cPanel). Lahr reference structure.
|
|-----------|---------|
|
||||||
3. [02-wordpress-to-html-migration.md](02-wordpress-to-html-migration.md) — The migration playbook
|
| `local-image-generation/` | Full local pipeline: ComfyUI setup, FLUX.1 Schnell images, Wan 2.2 video, prompt guide, quality levers |
|
||||||
4. [03-build-pipeline.md](03-build-pipeline.md) — JSON data + HTML template + Python build script
|
| `image-gen-workflow/` | Cloud API workflow (Google Imagen 4). Paid client budgets only. |
|
||||||
5. [04-content-rules.md](04-content-rules.md) — Writing standards (no em-dashes, no fake metrics)
|
| `wp-divi-pipeline-to-am-stack/` | End-to-end pipeline: .wpress archive to Stack A deployment |
|
||||||
6. [05-mobile-responsive.md](05-mobile-responsive.md) — Breakpoints, mobile nav, viewport testing
|
| `tools/` | Shared scripts (verify-protection.sh, etc.) |
|
||||||
7. [06-seo-meta.md](06-seo-meta.md) — Title, meta, canonical, keywords, schema, og:, robots.txt, sitemap. Includes lahr examples.
|
| `build/` | Build utilities |
|
||||||
8. [07-form-handling.md](07-form-handling.md) — Resend API + Python stdlib service pattern
|
|
||||||
9. [08-deployment-docker.md](08-deployment-docker.md) — Universal deployment: Docker+nginx (Path A) AND cPanel+Apache (Path B). Universal project checklist.
|
|
||||||
10. [09-domain-email-dns.md](09-domain-email-dns.md) — Resend domain verification, SPF/DKIM/DMARC
|
|
||||||
11. [10-testing-verification.md](10-testing-verification.md) — Playwright checks before declaring done
|
|
||||||
12. [11-healthcare-regulated-credentials.md](11-healthcare-regulated-credentials.md) — Licensure copy compliance for healthcare clients (MHC-LP, LMHC, supervision disclosure)
|
|
||||||
13. [12-image-assets.md](12-image-assets.md) — WebP requirement, sizing targets, local generation (FLUX.1 Schnell), convert-to-webp.py
|
|
||||||
14. [13-reference-site-visual-audit.md](13-reference-site-visual-audit.md) — Playwright Firefox scroll-capture + frame-strip + pin-transition annotation. Output skeleton + schema mapping for any client-cited reference URL.
|
|
||||||
15. [14-php-app-stack.md](14-php-app-stack.md) — When to use PHP + Docker instead of static HTML. Server-side processing, encryption, auth patterns.
|
|
||||||
|
|
||||||
## Image generation workflow
|
## Image generation
|
||||||
|
|
||||||
See [local-image-generation/](local-image-generation/) for the full local pipeline:
|
Default: Google Imagen API (imagen-4.0-generate-001) with allotted quota per project.
|
||||||
- [01-comfyui-setup.md](local-image-generation/01-comfyui-setup.md) — ComfyUI install, venv, GPU notes
|
See `image-gen-workflow/` for the workflow, model selection, and prompt patterns.
|
||||||
- [02-flux-images.md](local-image-generation/02-flux-images.md) — FLUX.1 Schnell image pipeline
|
|
||||||
- [03-wan-video.md](local-image-generation/03-wan-video.md) — Wan 2.2 image-to-video pipeline
|
|
||||||
- [04-prompt-guide.md](local-image-generation/04-prompt-guide.md) — Lens, angle, depth-of-field prompt patterns
|
|
||||||
- [05-quality-levers.md](local-image-generation/05-quality-levers.md) — Prompt, steps, model size: decision matrix for fixing output quality
|
|
||||||
|
|
||||||
Default stack (free, no API cost): FLUX.1 Schnell GGUF (images) + Wan 2.2 GGUF (video) via ComfyUI
|
All output: `.webp` only in production.
|
||||||
All output: `.webp` only — see `12-image-assets.md`
|
|
||||||
|
|
||||||
Cloud APIs (Google Veo, Imagen 4, Gemini video): only when client has explicit paid media budget.
|
|
||||||
Local generation is the default for all Arising Media client projects.
|
|
||||||
|
|
||||||
## Universal project file checklist
|
## Universal project file checklist
|
||||||
|
|
||||||
Every project must include ALL of these before first commit:
|
Every project must include ALL of these before first deploy:
|
||||||
|
|
||||||
```
|
```
|
||||||
Dockerfile Docker/VPS — nginx web container
|
Dockerfile Docker/VPS: nginx web container
|
||||||
docker-compose.yml Docker/VPS — service orchestration
|
docker-compose.yml Stack B/C only. Stack A uses raw docker commands.
|
||||||
nginx.conf Docker/VPS — routing, security headers, gzip
|
nginx.conf Docker/VPS: routing, security headers, gzip
|
||||||
.htaccess cPanel/Apache — clean URLs, deny sensitive files
|
.htaccess cPanel/Apache: clean URLs, deny sensitive files
|
||||||
.cpanel.yml cPanel Git — copy files to webroot on deploy
|
.cpanel.yml cPanel Git: copy files to webroot on deploy
|
||||||
.dockerignore keeps secrets and tools out of Docker image
|
.dockerignore keeps secrets and tools out of Docker image
|
||||||
.gitignore keeps .env and secrets out of git
|
.gitignore keeps .env and secrets out of git
|
||||||
robots.txt both paths
|
robots.txt both paths
|
||||||
sitemap.xml both paths
|
sitemap.xml both paths
|
||||||
llms.txt both paths — AI crawler documentation (see 06-seo-meta.md)
|
llms.txt both paths. AI crawler documentation (see OPTIMIZATION.md)
|
||||||
404.html both paths
|
404.html both paths
|
||||||
500.html both paths
|
500.html both paths
|
||||||
```
|
```
|
||||||
|
|
||||||
## Reference projects
|
## Reference projects
|
||||||
|
|
||||||
- `lahrcarpetcleaning.com` — **primary reference**: universal deployment, directory-style URLs, WebP images, cPanel Git, mobile nav, FLUX image generation
|
- `lahrcarpetcleaning.com`: primary reference. Universal deployment, directory-style URLs, WebP images, cPanel Git, mobile nav, FLUX image generation.
|
||||||
- `floorithardwoodfloors.com` — first WP-to-static migration with Docker stack
|
- `arisingmedia.us`: Stack A reference. PHP router, SQLite, 10,000+ pages.
|
||||||
- `backforge.nl` — simpler static site, no form API
|
- `quickconvert.us`: Stack C reference. PHP app, Stripe, encryption, auth.
|
||||||
|
|
||||||
## When to deviate
|
## When to deviate
|
||||||
|
|
||||||
These SOPs are the default. Deviate only when:
|
These SOPs are the default. Deviate only when:
|
||||||
- The client explicitly requires a different stack (CMS-managed editing, e-commerce with Shopify/Woo, etc.)
|
- The client explicitly requires a different stack (CMS-managed editing, e-commerce, etc.)
|
||||||
- A required feature literally cannot be done with this stack
|
- A required feature cannot be done with this stack
|
||||||
|
|
||||||
Document the deviation in the project's own `README.md` so future maintainers
|
Document the deviation in the project's own `README.md`.
|
||||||
know what is and is not standard.
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# STACK — Architecture, Deployment, and Build Pipeline
|
# STACK: Architecture, Deployment, and Build Pipeline
|
||||||
Author: Andre Cobham / Arising Media
|
Author: Andre Cobham / Arising Media
|
||||||
Updated: 2026-06-09
|
Updated: 2026-06-09
|
||||||
|
|
||||||
@@ -6,19 +6,19 @@ Updated: 2026-06-09
|
|||||||
|
|
||||||
Two primary stacks. Pick based on page count and update frequency.
|
Two primary stacks. Pick based on page count and update frequency.
|
||||||
|
|
||||||
### Stack A — PHP Router + SQLite (50+ pages, standard as of 2026-05-21)
|
### Stack A: PHP Router + SQLite (50+ pages, standard as of 2026-05-21)
|
||||||
|
|
||||||
- **PHP Router** — `router.php` dispatches every content URL to the correct PHP template. Edit one template = entire page class updates on next request. No find-and-replace. No file edits.
|
- **PHP Router**: `router.php` dispatches every content URL to the correct PHP template. Edit one template = entire page class updates on next request. No find-and-replace. No file edits.
|
||||||
- **SQLite** — single-file content DB. `pages.sqlite` holds all page content (title, meta, sections JSON, schema). 10,000 rows = 5MB. Sub-millisecond reads. No server process.
|
- **SQLite**: single-file content DB. `pages.sqlite` holds all page content (title, meta, sections JSON, schema). 10,000 rows = 5MB. Sub-millisecond reads. No server process.
|
||||||
- **Vanilla JavaScript** — no frameworks. `fetch`, `IntersectionObserver`, `querySelector`
|
- **Vanilla JavaScript**: no frameworks. `fetch`, `IntersectionObserver`, `querySelector`
|
||||||
- **Plain CSS** — `tokens.css` (design tokens) + `main.css` (components). No Sass, no Tailwind
|
- **Plain CSS**: `tokens.css` (design tokens) + `main.css` (components). No Sass, no Tailwind
|
||||||
- **Docker + nginx** — nginx routes `/assets/*` directly; all content URLs → PHP-FPM → router.php
|
- **Docker + nginx**: nginx routes `/assets/*` directly; all content URLs → PHP-FPM → router.php
|
||||||
- **Resend** — transactional email via `/api/contact.php`
|
- **Resend**: transactional email via `/api/contact.php`
|
||||||
- **Reference:** `arisingmedia.us` — 10,000+ pages
|
- **Reference:** `arisingmedia.us`: 10,000+ pages
|
||||||
|
|
||||||
### Stack B — Static HTML (fewer than 50 pages)
|
### Stack B: Static HTML (fewer than 50 pages)
|
||||||
|
|
||||||
- **Static HTML** — every page is a `.html` file on disk
|
- **Static HTML**: every page is a `.html` file on disk
|
||||||
- Same JS, CSS, Docker, nginx, Resend as Stack A
|
- Same JS, CSS, Docker, nginx, Resend as Stack A
|
||||||
- Python 3 stdlib for build scripts (no pip)
|
- Python 3 stdlib for build scripts (no pip)
|
||||||
- **Reference:** `lahrcarpetcleaning.com`
|
- **Reference:** `lahrcarpetcleaning.com`
|
||||||
@@ -36,11 +36,11 @@ Two primary stacks. Pick based on page count and update frequency.
|
|||||||
|
|
||||||
### Why This Stack
|
### Why This Stack
|
||||||
|
|
||||||
1. **Performance** — a static HTML page with vanilla JS loads in <100ms with no parse cost from frameworks
|
1. **Performance**: a static HTML page with vanilla JS loads in <100ms with no parse cost from frameworks
|
||||||
2. **Longevity** — no dependency rot. A site we build today still works in 10 years with no maintenance
|
2. **Longevity**: no dependency rot. A site we build today still works in 10 years with no maintenance
|
||||||
3. **Security** — no `npm audit` warnings, no supply-chain attack vectors, no transitive deps to patch
|
3. **Security**: no `npm audit` warnings, no supply-chain attack vectors, no transitive deps to patch
|
||||||
4. **Auditability** — every line on the site is something we wrote and can read in plain text
|
4. **Auditability**: every line on the site is something we wrote and can read in plain text
|
||||||
5. **Hosting** — a static folder + tiny Python container fits in the smallest VM tier any provider sells
|
5. **Hosting**: a static folder + tiny Python container fits in the smallest VM tier any provider sells
|
||||||
|
|
||||||
### When to Add a Server-Side Service
|
### When to Add a Server-Side Service
|
||||||
|
|
||||||
@@ -121,7 +121,7 @@ Contains ONLY what's needed to run `docker compose up`.
|
|||||||
├── api/ # form-submit Python service (if used)
|
├── api/ # form-submit Python service (if used)
|
||||||
│ ├── server.py
|
│ ├── server.py
|
||||||
│ ├── Dockerfile
|
│ ├── Dockerfile
|
||||||
│ ├── .env # gitignored — Resend key, etc.
|
│ ├── .env # gitignored: Resend key, etc.
|
||||||
│ └── .env.example
|
│ └── .env.example
|
||||||
├── Dockerfile # nginx web container
|
├── Dockerfile # nginx web container
|
||||||
├── nginx.conf
|
├── nginx.conf
|
||||||
@@ -145,7 +145,7 @@ notes, raw assets). This is the dev/maintenance copy. NOT what gets deployed.
|
|||||||
Build scripts, JSON data, and notes go into `.planning/` to keep root clean and
|
Build scripts, JSON data, and notes go into `.planning/` to keep root clean and
|
||||||
prevent accidental web exposure.
|
prevent accidental web exposure.
|
||||||
|
|
||||||
### URL Structure — Two Valid Patterns
|
### URL Structure: Two Valid Patterns
|
||||||
|
|
||||||
#### Pattern A: Flat HTML (default for Docker/nginx projects)
|
#### Pattern A: Flat HTML (default for Docker/nginx projects)
|
||||||
|
|
||||||
@@ -156,7 +156,7 @@ Why flat:
|
|||||||
- One file = one page, no `/index.html` confusion
|
- One file = one page, no `/index.html` confusion
|
||||||
- Easier sitemap generation
|
- Easier sitemap generation
|
||||||
- `<a href>` links are unambiguous
|
- `<a href>` links are unambiguous
|
||||||
- Crawl budget benefit — Google indexes one URL per page, not two
|
- Crawl budget benefit: Google indexes one URL per page, not two
|
||||||
|
|
||||||
#### Pattern B: Directory-style (default for cPanel/Apache projects)
|
#### Pattern B: Directory-style (default for cPanel/Apache projects)
|
||||||
|
|
||||||
@@ -242,9 +242,9 @@ directly. Build scripts are for repetition, not for everything.
|
|||||||
|
|
||||||
Three files per template family:
|
Three files per template family:
|
||||||
|
|
||||||
1. **`data/{thing}.json`** — array of objects, one per page
|
1. **`data/{thing}.json`**: array of objects, one per page
|
||||||
2. **`{thing}/_template.html`** — HTML with `{{placeholder}}` markers
|
2. **`{thing}/_template.html`**: HTML with `{{placeholder}}` markers
|
||||||
3. **`build_{thing}.py`** — stdlib Python, stamps template with data
|
3. **`build_{thing}.py`**: stdlib Python, stamps template with data
|
||||||
|
|
||||||
#### Example: locations.json
|
#### Example: locations.json
|
||||||
|
|
||||||
@@ -327,7 +327,7 @@ if __name__ == "__main__":
|
|||||||
### Rules
|
### Rules
|
||||||
|
|
||||||
1. **Source of truth is JSON, not HTML.** When content needs to change, edit the
|
1. **Source of truth is JSON, not HTML.** When content needs to change, edit the
|
||||||
JSON and re-run the build script. Never hand-edit a generated `.html` file —
|
JSON and re-run the build script. Never hand-edit a generated `.html` file :
|
||||||
the next build will overwrite your changes.
|
the next build will overwrite your changes.
|
||||||
|
|
||||||
2. **Generated files land in the same folder as their template.** Do not nest
|
2. **Generated files land in the same folder as their template.** Do not nest
|
||||||
@@ -345,7 +345,7 @@ if __name__ == "__main__":
|
|||||||
|
|
||||||
5. **Build is idempotent.** Running it twice produces identical files.
|
5. **Build is idempotent.** Running it twice produces identical files.
|
||||||
|
|
||||||
### Stamping Rules — Escaping
|
### Stamping Rules: Escaping
|
||||||
|
|
||||||
When a JSON value gets stamped into an HTML attribute or `<title>`, special
|
When a JSON value gets stamped into an HTML attribute or `<title>`, special
|
||||||
characters can break the page. Use these rules:
|
characters can break the page. Use these rules:
|
||||||
@@ -376,20 +376,20 @@ After build, sync the rendered files to deployment.
|
|||||||
The playbook for migrating a WordPress (Divi, Elementor, classic, whatever) site
|
The playbook for migrating a WordPress (Divi, Elementor, classic, whatever) site
|
||||||
to vanilla static HTML.
|
to vanilla static HTML.
|
||||||
|
|
||||||
### Phase 1 — Capture Source
|
### Phase 1: Capture Source
|
||||||
|
|
||||||
Before touching anything, capture the current site so nothing is lost.
|
Before touching anything, capture the current site so nothing is lost.
|
||||||
|
|
||||||
1. **Database dump** — `wp db export ${domain}.sql --add-drop-table`
|
1. **Database dump**: `wp db export ${domain}.sql --add-drop-table`
|
||||||
2. **Wp-content snapshot** — tar the entire `wp-content/` (themes, plugins, uploads)
|
2. **Wp-content snapshot**: tar the entire `wp-content/` (themes, plugins, uploads)
|
||||||
3. **Crawl the live site** — use `wget --mirror --convert-links --adjust-extension --page-requisites --no-parent https://{domain}` to capture rendered HTML + all assets
|
3. **Crawl the live site**: use `wget --mirror --convert-links --adjust-extension --page-requisites --no-parent https://{domain}` to capture rendered HTML + all assets
|
||||||
4. **Inventory pages** — list every URL returning 200 (use the sitemap if it has one)
|
4. **Inventory pages**: list every URL returning 200 (use the sitemap if it has one)
|
||||||
5. **Inventory forms** — note every Gravity Form / Contact Form 7 / etc. field-by-field
|
5. **Inventory forms**: note every Gravity Form / Contact Form 7 / etc. field-by-field
|
||||||
6. **Inventory dynamic features** — search, comments, members, anything truly dynamic
|
6. **Inventory dynamic features**: search, comments, members, anything truly dynamic
|
||||||
|
|
||||||
Save all of this in the project's `.planning/` folder.
|
Save all of this in the project's `.planning/` folder.
|
||||||
|
|
||||||
### Phase 2 — Decide What to Keep
|
### Phase 2: Decide What to Keep
|
||||||
|
|
||||||
Re-design pass. Most WP sites have:
|
Re-design pass. Most WP sites have:
|
||||||
- Bloated copy → cut by 30-50%
|
- Bloated copy → cut by 30-50%
|
||||||
@@ -400,7 +400,7 @@ Re-design pass. Most WP sites have:
|
|||||||
|
|
||||||
Show the client a wireframe of the simplified structure before building anything.
|
Show the client a wireframe of the simplified structure before building anything.
|
||||||
|
|
||||||
### Phase 3 — Information Architecture
|
### Phase 3: Information Architecture
|
||||||
|
|
||||||
Standard structure for a small business:
|
Standard structure for a small business:
|
||||||
|
|
||||||
@@ -419,19 +419,19 @@ Standard structure for a small business:
|
|||||||
For each location and each service: one flat `.html` page generated from JSON +
|
For each location and each service: one flat `.html` page generated from JSON +
|
||||||
template.
|
template.
|
||||||
|
|
||||||
### Phase 4 — Build
|
### Phase 4: Build
|
||||||
|
|
||||||
1. Set up source folder per `01-project-structure.md`
|
1. Set up source folder per the Project Structure section in STACK.md
|
||||||
2. Write `assets/css/main.css` (variables, reset, typography, layout)
|
2. Write `assets/css/main.css` (variables, reset, typography, layout)
|
||||||
3. Write `assets/css/components.css` (header, footer, hero, cards, forms)
|
3. Write `assets/css/components.css` (header, footer, hero, cards, forms)
|
||||||
4. Write `components/header.html` and `components/footer.html`
|
4. Write `components/header.html` and `components/footer.html`
|
||||||
5. Write `assets/js/components.js` (fetch + inject header/footer)
|
5. Write `assets/js/components.js` (fetch + inject header/footer)
|
||||||
6. Write `assets/js/main.js` (scroll animations, anything page-wide)
|
6. Write `assets/js/main.js` (scroll animations, anything page-wide)
|
||||||
7. Build `index.html` first — this is the design system in working form
|
7. Build `index.html` first: this is the design system in working form
|
||||||
8. Generate location and service detail pages from JSON
|
8. Generate location and service detail pages from JSON
|
||||||
9. Build remaining pages: about, contact, reviews, blog index
|
9. Build remaining pages: about, contact, reviews, blog index
|
||||||
|
|
||||||
### Phase 5 — Forms
|
### Phase 5: Forms
|
||||||
|
|
||||||
If the WP site had Gravity Forms or similar, build a vanilla replacement:
|
If the WP site had Gravity Forms or similar, build a vanilla replacement:
|
||||||
- HTML form in `contact/index.html` (and inline on service/location pages if needed)
|
- HTML form in `contact/index.html` (and inline on service/location pages if needed)
|
||||||
@@ -439,7 +439,7 @@ If the WP site had Gravity Forms or similar, build a vanilla replacement:
|
|||||||
- POST to `/api/estimate` (or similar) handled by Python stdlib service
|
- POST to `/api/estimate` (or similar) handled by Python stdlib service
|
||||||
- Server-side validation, reCAPTCHA verification, send via Resend
|
- Server-side validation, reCAPTCHA verification, send via Resend
|
||||||
|
|
||||||
### Phase 6 — SEO Parity
|
### Phase 6: SEO Parity
|
||||||
|
|
||||||
Before launch, every old URL must either:
|
Before launch, every old URL must either:
|
||||||
- Have a matching new URL with the same or better content, OR
|
- Have a matching new URL with the same or better content, OR
|
||||||
@@ -461,7 +461,7 @@ Per-page parity checklist:
|
|||||||
- Image alt text preserved or improved
|
- Image alt text preserved or improved
|
||||||
- Schema.org JSON-LD added (`LocalBusiness`, `Service`, `BreadcrumbList`)
|
- Schema.org JSON-LD added (`LocalBusiness`, `Service`, `BreadcrumbList`)
|
||||||
|
|
||||||
### Phase 7 — Switch DNS / Cutover
|
### Phase 7: Switch DNS / Cutover
|
||||||
|
|
||||||
1. Deploy the static site to a separate URL first (`new.{domain}`) for client review
|
1. Deploy the static site to a separate URL first (`new.{domain}`) for client review
|
||||||
2. Once approved, point production DNS to the new container
|
2. Once approved, point production DNS to the new container
|
||||||
@@ -469,16 +469,16 @@ Per-page parity checklist:
|
|||||||
4. Submit new sitemap to Google Search Console
|
4. Submit new sitemap to Google Search Console
|
||||||
5. Use Search Console URL inspection on 5-10 key pages to confirm indexing
|
5. Use Search Console URL inspection on 5-10 key pages to confirm indexing
|
||||||
|
|
||||||
### Phase 8 — Post-Launch
|
### Phase 8: Post-Launch
|
||||||
|
|
||||||
- Monitor Search Console for crawl errors / 404s, fix in nginx as redirects
|
- Monitor Search Console for crawl errors / 404s, fix in nginx as redirects
|
||||||
- Monitor form submissions — first real lead through the new form is the
|
- Monitor form submissions: first real lead through the new form is the
|
||||||
ultimate "it works" check
|
ultimate "it works" check
|
||||||
- Decommission WP only after 30 days of clean operation
|
- Decommission WP only after 30 days of clean operation
|
||||||
|
|
||||||
### What NOT to Do
|
### What NOT to Do
|
||||||
|
|
||||||
- Do not run a "headless WordPress" or "WordPress as API" — that defeats the
|
- Do not run a "headless WordPress" or "WordPress as API": that defeats the
|
||||||
whole point. Static means static.
|
whole point. Static means static.
|
||||||
- Do not use a static-site-generator tool (Hugo, 11ty, Jekyll, Astro, Next.js
|
- Do not use a static-site-generator tool (Hugo, 11ty, Jekyll, Astro, Next.js
|
||||||
static export). We hand-write HTML and use small Python build scripts only
|
static export). We hand-write HTML and use small Python build scripts only
|
||||||
@@ -506,7 +506,7 @@ Takes a single `.wpress` archive (All-in-One WP Migration backup) and produces:
|
|||||||
|
|
||||||
The goal is NOT a 1:1 copy. The goal is:
|
The goal is NOT a 1:1 copy. The goal is:
|
||||||
1. Preserve all content, SEO equity, and brand identity
|
1. Preserve all content, SEO equity, and brand identity
|
||||||
2. ENHANCE the design — cleaner, faster, more modern
|
2. ENHANCE the design: cleaner, faster, more modern
|
||||||
3. Remove all WordPress / Divi bloat (plugin CSS, shortcode residue, 300KB JS bundles)
|
3. Remove all WordPress / Divi bloat (plugin CSS, shortcode residue, 300KB JS bundles)
|
||||||
4. Produce a site that loads in <2s on mobile and scores 95+ on Lighthouse
|
4. Produce a site that loads in <2s on mobile and scores 95+ on Lighthouse
|
||||||
|
|
||||||
@@ -551,14 +551,14 @@ All scripts live in `.am-webdesign-sops/wp-divi-pipeline/scripts/`.
|
|||||||
| `extract_design.py` | 4 | Pull Divi theme options → design-system.json |
|
| `extract_design.py` | 4 | Pull Divi theme options → design-system.json |
|
||||||
| `extract_media.py` | 5 | Catalog uploads/, emit media-manifest.json |
|
| `extract_media.py` | 5 | Catalog uploads/, emit media-manifest.json |
|
||||||
| `convert_images.py` | 5 | Batch convert images → WebP |
|
| `convert_images.py` | 5 | Batch convert images → WebP |
|
||||||
| `run_pipeline.sh` | 0-7 | Master script — runs all phases in order |
|
| `run_pipeline.sh` | 0-7 | Master script: runs all phases in order |
|
||||||
|
|
||||||
### Per-Project Working Directory
|
### Per-Project Working Directory
|
||||||
|
|
||||||
```
|
```
|
||||||
{domain}/
|
{domain}/
|
||||||
└── .planning/
|
└── .planning/
|
||||||
├── vibrantyou-yoga-YYYYMMDD-*.wpress ← source archive (never modify)
|
├── {domain}-YYYYMMDD-*.wpress ← source archive (never modify)
|
||||||
├── wpress-extract/ ← Phase 1 output (gitignored)
|
├── wpress-extract/ ← Phase 1 output (gitignored)
|
||||||
│ ├── package.json ← archive metadata
|
│ ├── package.json ← archive metadata
|
||||||
│ ├── database.sql ← MySQL dump
|
│ ├── database.sql ← MySQL dump
|
||||||
@@ -593,7 +593,7 @@ The archive ends when a header of all null bytes is encountered, or EOF.
|
|||||||
Extraction script:
|
Extraction script:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python3 /home/sirdrez/arisingmedia-websites/.am-webdesign-sops/wp-divi-pipeline/scripts/extract_wpress.py \
|
python3 /home/sirdrez/arisingmedia-websites/.am-webdesign-sops/wp-divi-pipeline-to-am-stack/scripts/extract_wpress.py \
|
||||||
/home/sirdrez/arisingmedia-websites/{domain}/.planning/{file}.wpress \
|
/home/sirdrez/arisingmedia-websites/{domain}/.planning/{file}.wpress \
|
||||||
/home/sirdrez/arisingmedia-websites/{domain}/.planning/wpress-extract/
|
/home/sirdrez/arisingmedia-websites/{domain}/.planning/wpress-extract/
|
||||||
```
|
```
|
||||||
@@ -610,9 +610,9 @@ python3 /home/sirdrez/arisingmedia-websites/.am-webdesign-sops/wp-divi-pipeline/
|
|||||||
```
|
```
|
||||||
|
|
||||||
Outputs three files into `.planning/data/`:
|
Outputs three files into `.planning/data/`:
|
||||||
- `pages.json` — all published pages/posts with content and SEO meta
|
- `pages.json`: all published pages/posts with content and SEO meta
|
||||||
- `design-system.json` — colors, fonts, Divi settings
|
- `design-system.json`: colors, fonts, Divi settings
|
||||||
- `site-info.json` — domain, plugin list, WP version, Divi version
|
- `site-info.json`: domain, plugin list, WP version, Divi version
|
||||||
|
|
||||||
### Divi 5 Content Extraction
|
### Divi 5 Content Extraction
|
||||||
|
|
||||||
@@ -654,7 +654,7 @@ Strip Divi class/attribute noise using `clean_divi_html()` from `divi_to_html.py
|
|||||||
from divi_to_html import clean_divi_html, rewrite_internal_links
|
from divi_to_html import clean_divi_html, rewrite_internal_links
|
||||||
|
|
||||||
cleaned = clean_divi_html(raw_html)
|
cleaned = clean_divi_html(raw_html)
|
||||||
cleaned = rewrite_internal_links(cleaned, staging_hosts=("vibrantyou.yoga",))
|
cleaned = rewrite_internal_links(cleaned, staging_hosts=("{domain}",))
|
||||||
```
|
```
|
||||||
|
|
||||||
### Design System Extraction
|
### Design System Extraction
|
||||||
@@ -712,13 +712,13 @@ full 5-step scale around the primary hue:
|
|||||||
Map extracted Divi content into AM HTML templates.
|
Map extracted Divi content into AM HTML templates.
|
||||||
|
|
||||||
Build order:
|
Build order:
|
||||||
1. `src/assets/css/main.css` — design tokens, reset, typography, layout grid
|
1. `src/assets/css/main.css`: design tokens, reset, typography, layout grid
|
||||||
2. `src/assets/css/components.css` — header, footer, hero, cards, forms, nav
|
2. `src/assets/css/components.css`: header, footer, hero, cards, forms, nav
|
||||||
3. `src/components/header.html` — navigation
|
3. `src/components/header.html`: navigation
|
||||||
4. `src/components/footer.html` — footer links, contact info
|
4. `src/components/footer.html`: footer links, contact info
|
||||||
5. `src/assets/js/components.js` — fetch + inject header/footer
|
5. `src/assets/js/components.js`: fetch + inject header/footer
|
||||||
6. `src/assets/js/main.js` — scroll animations, intersection observer
|
6. `src/assets/js/main.js`: scroll animations, intersection observer
|
||||||
7. `src/index.html` — home page (this IS the design system in working form)
|
7. `src/index.html`: home page (this IS the design system in working form)
|
||||||
8. Remaining pages: about, classes, contact, blog
|
8. Remaining pages: about, classes, contact, blog
|
||||||
9. `src/robots.txt`, `src/sitemap.xml`, `src/404.html`, `src/500.html`
|
9. `src/robots.txt`, `src/sitemap.xml`, `src/404.html`, `src/500.html`
|
||||||
|
|
||||||
@@ -790,7 +790,7 @@ Priority order for SEO fields:
|
|||||||
2. `post_title` with AM format appended: `{Title} | {Brand Name}`
|
2. `post_title` with AM format appended: `{Title} | {Brand Name}`
|
||||||
3. Never leave title as the raw WP default
|
3. Never leave title as the raw WP default
|
||||||
|
|
||||||
Rank Math title templates use `%` tokens — strip them and rebuild:
|
Rank Math title templates use `%` tokens: strip them and rebuild:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
import re
|
import re
|
||||||
@@ -837,7 +837,7 @@ grep -r "et_pb_\|wp:divi" $SITE --include="*.html"
|
|||||||
### Run Order (Complete Execution Sequence)
|
### Run Order (Complete Execution Sequence)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
export DOMAIN="vibrantyou.yoga"
|
export DOMAIN="{domain}"
|
||||||
export PROJECT="/home/sirdrez/arisingmedia-websites/$DOMAIN"
|
export PROJECT="/home/sirdrez/arisingmedia-websites/$DOMAIN"
|
||||||
export SOPS="/home/sirdrez/arisingmedia-websites/.am-webdesign-sops"
|
export SOPS="/home/sirdrez/arisingmedia-websites/.am-webdesign-sops"
|
||||||
export WPRESS=$(ls $PROJECT/.planning/*.wpress | head -1)
|
export WPRESS=$(ls $PROJECT/.planning/*.wpress | head -1)
|
||||||
@@ -854,7 +854,7 @@ python3 $SOPS/wp-divi-pipeline/scripts/analyze_db.py "$PROJECT/.planning/wpress-
|
|||||||
# Phase 3: Content extraction (Divi 5 example)
|
# Phase 3: Content extraction (Divi 5 example)
|
||||||
python3 $SOPS/wp-divi-pipeline/scripts/extract_divi5.py "$PROJECT/.planning/data/pages.json" "$PROJECT/.planning/data/content/"
|
python3 $SOPS/wp-divi-pipeline/scripts/extract_divi5.py "$PROJECT/.planning/data/pages.json" "$PROJECT/.planning/data/content/"
|
||||||
|
|
||||||
# Phase 4: Design system (manual — read design-system.json, write main.css)
|
# Phase 4: Design system (manual: read design-system.json, write main.css)
|
||||||
|
|
||||||
# Phase 5: Media migration
|
# Phase 5: Media migration
|
||||||
find $PROJECT/.planning/wpress-extract/uploads -type f \( -name "*.jpg" -o -name "*.png" \) | \
|
find $PROJECT/.planning/wpress-extract/uploads -type f \( -name "*.jpg" -o -name "*.png" \) | \
|
||||||
@@ -870,7 +870,7 @@ for img in *.jpg *.png; do
|
|||||||
cwebp -q 82 "$img" -o "${img%.*}.webp" && rm "$img"
|
cwebp -q 82 "$img" -o "${img%.*}.webp" && rm "$img"
|
||||||
done
|
done
|
||||||
|
|
||||||
# Phase 6: Build HTML (manual — per 05-content-migration.md)
|
# Phase 6: Build HTML (manual: per 05-content-migration.md)
|
||||||
|
|
||||||
# Phase 7: SEO audit
|
# Phase 7: SEO audit
|
||||||
cd $PROJECT/src
|
cd $PROJECT/src
|
||||||
@@ -930,17 +930,17 @@ Port assignments are unique per project. Track in
|
|||||||
|
|
||||||
### Dockerfile (nginx web container)
|
### Dockerfile (nginx web container)
|
||||||
|
|
||||||
CRITICAL — the Dockerfile must explicitly list which folders to copy. Never use
|
CRITICAL: the Dockerfile must explicitly list which folders to copy. Never use
|
||||||
`COPY . /usr/share/nginx/html/` because that copies `.env`, `Dockerfile`,
|
`COPY . /usr/share/nginx/html/` because that copies `.env`, `Dockerfile`,
|
||||||
build scripts, etc. into the web root where they become URL-accessible.
|
build scripts, etc. into the web root where they become URL-accessible.
|
||||||
|
|
||||||
```dockerfile
|
```dockerfile
|
||||||
FROM nginx:alpine
|
FROM nginx:alpine
|
||||||
|
|
||||||
# nginx config — server-only, never served as a static file
|
# nginx config: server-only, never served as a static file
|
||||||
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
COPY nginx.conf /etc/nginx/conf.d/default.conf
|
||||||
|
|
||||||
# Public website only — explicit list, no wildcards
|
# Public website only: explicit list, no wildcards
|
||||||
COPY index.html /usr/share/nginx/html/
|
COPY index.html /usr/share/nginx/html/
|
||||||
COPY assets /usr/share/nginx/html/assets/
|
COPY assets /usr/share/nginx/html/assets/
|
||||||
COPY components /usr/share/nginx/html/components/
|
COPY components /usr/share/nginx/html/components/
|
||||||
@@ -975,7 +975,7 @@ server {
|
|||||||
root /usr/share/nginx/html;
|
root /usr/share/nginx/html;
|
||||||
index index.html;
|
index index.html;
|
||||||
|
|
||||||
# Defense in depth — deny dotfiles, configs, scripts, source files
|
# Defense in depth: deny dotfiles, configs, scripts, source files
|
||||||
location ~ /\. {
|
location ~ /\. {
|
||||||
deny all;
|
deny all;
|
||||||
return 404;
|
return 404;
|
||||||
@@ -989,7 +989,7 @@ server {
|
|||||||
return 404;
|
return 404;
|
||||||
}
|
}
|
||||||
|
|
||||||
# API proxy — strip /api/ prefix, forward to Python service
|
# API proxy: strip /api/ prefix, forward to Python service
|
||||||
location /api/ {
|
location /api/ {
|
||||||
proxy_pass http://api:3001/;
|
proxy_pass http://api:3001/;
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
@@ -1000,7 +1000,7 @@ server {
|
|||||||
proxy_connect_timeout 5s;
|
proxy_connect_timeout 5s;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Flat HTML routing — /locations/buffalo serves /locations/buffalo.html
|
# Flat HTML routing: /locations/buffalo serves /locations/buffalo.html
|
||||||
location / {
|
location / {
|
||||||
try_files $uri $uri/ $uri.html =404;
|
try_files $uri $uri/ $uri.html =404;
|
||||||
}
|
}
|
||||||
@@ -1100,10 +1100,10 @@ scripts, `.git/`, etc.) and fails if any returns 200.
|
|||||||
```
|
```
|
||||||
|
|
||||||
Exit codes:
|
Exit codes:
|
||||||
- `0` PASS — every sensitive path 404, every required path reachable.
|
- `0` PASS: every sensitive path 404, every required path reachable.
|
||||||
- `0` PASS (with warnings) — protection clean but `/robots.txt` or
|
- `0` PASS (with warnings): protection clean but `/robots.txt` or
|
||||||
`/sitemap.xml` missing (content gap, not a leak).
|
`/sitemap.xml` missing (content gap, not a leak).
|
||||||
- `1` FAIL — at least one sensitive path returned 200, or `/` is unreachable.
|
- `1` FAIL: at least one sensitive path returned 200, or `/` is unreachable.
|
||||||
|
|
||||||
Run it manually after every `docker compose up -d --build`. Wire it into CI
|
Run it manually after every `docker compose up -d --build`. Wire it into CI
|
||||||
once the site has a remote pipeline. Treat a FAIL as a deploy rollback.
|
once the site has a remote pipeline. Treat a FAIL as a deploy rollback.
|
||||||
@@ -1132,7 +1132,7 @@ compose project:
|
|||||||
docker stop {container-name}
|
docker stop {container-name}
|
||||||
docker rm {container-name}
|
docker rm {container-name}
|
||||||
|
|
||||||
# Now bring up from the renamed folder — clean start
|
# Now bring up from the renamed folder: clean start
|
||||||
docker compose -f /path/to/renamed-folder/docker-compose.yml up -d
|
docker compose -f /path/to/renamed-folder/docker-compose.yml up -d
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -1152,7 +1152,7 @@ WHM, Bluehost, HostGator, SiteGround, etc.) instead of a VPS running Docker.
|
|||||||
### Key Rule: Repo Path ≠ Webroot
|
### Key Rule: Repo Path ≠ Webroot
|
||||||
|
|
||||||
cPanel Git requires an EMPTY directory as the repository path. The webroot
|
cPanel Git requires an EMPTY directory as the repository path. The webroot
|
||||||
(`public_html/{domain}/`) is never the repo path — cPanel rejects it if it
|
(`public_html/{domain}/`) is never the repo path: cPanel rejects it if it
|
||||||
already contains files.
|
already contains files.
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -1165,7 +1165,7 @@ Deploy target (webroot): /home/{username}/public_html/{domain}/
|
|||||||
1. cPanel → Git Version Control → Create Repository
|
1. cPanel → Git Version Control → Create Repository
|
||||||
2. Repository Path: `/home/{username}/repositories/{domain}/` (must be empty)
|
2. Repository Path: `/home/{username}/repositories/{domain}/` (must be empty)
|
||||||
3. Clone URL: your Git remote (GitHub, Bitbucket, etc.)
|
3. Clone URL: your Git remote (GitHub, Bitbucket, etc.)
|
||||||
4. cPanel clones into the repo path — never into the webroot
|
4. cPanel clones into the repo path: never into the webroot
|
||||||
|
|
||||||
### .cpanel.yml
|
### .cpanel.yml
|
||||||
|
|
||||||
@@ -1220,7 +1220,7 @@ deployment:
|
|||||||
1. Push to the connected remote (GitHub)
|
1. Push to the connected remote (GitHub)
|
||||||
2. cPanel → Git Version Control → Manage → Pull or Deploy
|
2. cPanel → Git Version Control → Manage → Pull or Deploy
|
||||||
3. cPanel runs the `.cpanel.yml` tasks, copying files to webroot
|
3. cPanel runs the `.cpanel.yml` tasks, copying files to webroot
|
||||||
4. Apache serves from webroot automatically — no nginx, no Docker
|
4. Apache serves from webroot automatically: no nginx, no Docker
|
||||||
|
|
||||||
### Apache vs nginx
|
### Apache vs nginx
|
||||||
|
|
||||||
@@ -1232,7 +1232,7 @@ Options -Indexes
|
|||||||
RewriteEngine On
|
RewriteEngine On
|
||||||
|
|
||||||
# Directory-style URLs: /services/carpet-cleaning/ → index.html inside that folder
|
# Directory-style URLs: /services/carpet-cleaning/ → index.html inside that folder
|
||||||
# Apache handles this automatically with DirectoryIndex — no extra rules needed
|
# Apache handles this automatically with DirectoryIndex: no extra rules needed
|
||||||
|
|
||||||
# Deny sensitive files
|
# Deny sensitive files
|
||||||
<FilesMatch "\.(py|yml|yaml|md|log|sh|env|conf|dockerfile)$">
|
<FilesMatch "\.(py|yml|yaml|md|log|sh|env|conf|dockerfile)$">
|
||||||
@@ -1312,7 +1312,7 @@ Lahrcarpetcleaning.com is the reference implementation for both paths.
|
|||||||
1. https://resend.com/domains → **Add Domain**
|
1. https://resend.com/domains → **Add Domain**
|
||||||
2. Enter the domain (the one you'll send FROM, not necessarily the website domain)
|
2. Enter the domain (the one you'll send FROM, not necessarily the website domain)
|
||||||
3. Resend gives 3-4 DNS records. Add them all in Cloudflare (or whatever DNS host)
|
3. Resend gives 3-4 DNS records. Add them all in Cloudflare (or whatever DNS host)
|
||||||
4. Wait 5-15 minutes, click **Verify** in Resend — all records must show green
|
4. Wait 5-15 minutes, click **Verify** in Resend: all records must show green
|
||||||
|
|
||||||
### Records Resend Provides
|
### Records Resend Provides
|
||||||
|
|
||||||
@@ -1324,7 +1324,7 @@ Lahrcarpetcleaning.com is the reference implementation for both paths.
|
|||||||
|
|
||||||
(Resend uses Amazon SES under the hood, hence `amazonses.com` in the SPF.)
|
(Resend uses Amazon SES under the hood, hence `amazonses.com` in the SPF.)
|
||||||
|
|
||||||
### DMARC — REQUIRED for Inbox Placement
|
### DMARC: REQUIRED for Inbox Placement
|
||||||
|
|
||||||
Without DMARC, Gmail flags otherwise-correctly-configured email as suspicious
|
Without DMARC, Gmail flags otherwise-correctly-configured email as suspicious
|
||||||
and routes it to spam. Resend doesn't auto-create this record. You must add it.
|
and routes it to spam. Resend doesn't auto-create this record. You must add it.
|
||||||
@@ -1334,9 +1334,9 @@ and routes it to spam. Resend doesn't auto-create this record. You must add it.
|
|||||||
| TXT | `_dmarc` | `v=DMARC1; p=none; rua=mailto:dev@{domain}` | DNS only | Auto |
|
| TXT | `_dmarc` | `v=DMARC1; p=none; rua=mailto:dev@{domain}` | DNS only | Auto |
|
||||||
|
|
||||||
Components:
|
Components:
|
||||||
- `v=DMARC1` — declares a DMARC policy exists
|
- `v=DMARC1`: declares a DMARC policy exists
|
||||||
- `p=none` — monitor mode, doesn't reject anything yet (safe to start)
|
- `p=none`: monitor mode, doesn't reject anything yet (safe to start)
|
||||||
- `rua=mailto:...` — DMARC failure reports go to this inbox (review weekly)
|
- `rua=mailto:...`: DMARC failure reports go to this inbox (review weekly)
|
||||||
|
|
||||||
After 30 days of clean DMARC reports with no false positives, optionally
|
After 30 days of clean DMARC reports with no false positives, optionally
|
||||||
upgrade to `p=quarantine` then `p=reject`.
|
upgrade to `p=quarantine` then `p=reject`.
|
||||||
@@ -1389,7 +1389,7 @@ Run this checklist:
|
|||||||
|
|
||||||
### Cloudflare-Specific Notes
|
### Cloudflare-Specific Notes
|
||||||
|
|
||||||
The user-agent quirk — Cloudflare in front of Resend's API blocks Python's default
|
The user-agent quirk: Cloudflare in front of Resend's API blocks Python's default
|
||||||
`User-Agent: Python-urllib/3.x`. Always set a custom `User-Agent` in the API request headers.
|
`User-Agent: Python-urllib/3.x`. Always set a custom `User-Agent` in the API request headers.
|
||||||
|
|
||||||
If the DNS provider is Cloudflare, ensure all Resend records have **proxy status: DNS only**
|
If the DNS provider is Cloudflare, ensure all Resend records have **proxy status: DNS only**
|
||||||
@@ -1404,7 +1404,7 @@ Rotate Resend API keys annually:
|
|||||||
4. Confirm a test submission still works
|
4. Confirm a test submission still works
|
||||||
5. Revoke the old key in Resend dashboard
|
5. Revoke the old key in Resend dashboard
|
||||||
|
|
||||||
### Resend HTTP 403 — Domain Not Verified
|
### Resend HTTP 403: Domain Not Verified
|
||||||
|
|
||||||
A 403 from the Resend API does NOT mean the API key is wrong. The specific
|
A 403 from the Resend API does NOT mean the API key is wrong. The specific
|
||||||
error is:
|
error is:
|
||||||
@@ -1435,7 +1435,7 @@ in Cloudflare, then click verify. Old key remains active until they remove it.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Form Handling — Resend
|
## Form Handling: Resend
|
||||||
|
|
||||||
Static sites can't send email by themselves. Every project that needs a
|
Static sites can't send email by themselves. Every project that needs a
|
||||||
contact form gets a small Python service running in its own Docker container,
|
contact form gets a small Python service running in its own Docker container,
|
||||||
@@ -1565,11 +1565,11 @@ are deduplicated by Resend automatically. This prevents:
|
|||||||
- API key in `.env` file, NOT in source control. `.gitignore` it.
|
- API key in `.env` file, NOT in source control. `.gitignore` it.
|
||||||
- API key NEVER reaches the browser bundle (only the server has it)
|
- API key NEVER reaches the browser bundle (only the server has it)
|
||||||
- `.env` file lives in `api/`, NOT in the nginx web root
|
- `.env` file lives in `api/`, NOT in the nginx web root
|
||||||
- Server-side validation on EVERY field — never trust client
|
- Server-side validation on EVERY field: never trust client
|
||||||
- HTML-escape every field rendered into the email body to prevent injection
|
- HTML-escape every field rendered into the email body to prevent injection
|
||||||
- Rate limit per IP (5 / 15 min default)
|
- Rate limit per IP (5 / 15 min default)
|
||||||
- 16 KB body cap — reject anything larger
|
- 16 KB body cap: reject anything larger
|
||||||
- 10-second upstream timeout — don't hold connections open
|
- 10-second upstream timeout: don't hold connections open
|
||||||
- CORS locked to the production domain only (`Access-Control-Allow-Origin: https://{domain}`)
|
- CORS locked to the production domain only (`Access-Control-Allow-Origin: https://{domain}`)
|
||||||
- reCAPTCHA v3 with score threshold (default 0.5) once secret is configured
|
- reCAPTCHA v3 with score threshold (default 0.5) once secret is configured
|
||||||
|
|
||||||
@@ -1650,7 +1650,7 @@ Use this pattern when a project requires server-side processing that static HTML
|
|||||||
- **PHP 8.3** (php:8.3-fpm-alpine base image)
|
- **PHP 8.3** (php:8.3-fpm-alpine base image)
|
||||||
- **Nginx** (Alpine package, same container via supervisord)
|
- **Nginx** (Alpine package, same container via supervisord)
|
||||||
- **SQLite** (pdo_sqlite extension, no separate DB container needed)
|
- **SQLite** (pdo_sqlite extension, no separate DB container needed)
|
||||||
- **libsodium** (built into PHP 8.x — use for all encryption)
|
- **libsodium** (built into PHP 8.x: use for all encryption)
|
||||||
- **ImageMagick** (pecl imagick for image processing)
|
- **ImageMagick** (pecl imagick for image processing)
|
||||||
- **msmtp** (SMTP relay for outbound email)
|
- **msmtp** (SMTP relay for outbound email)
|
||||||
- **supervisord** (manages nginx + php-fpm + crond in one container)
|
- **supervisord** (manages nginx + php-fpm + crond in one container)
|
||||||
@@ -1697,19 +1697,19 @@ project/
|
|||||||
|
|
||||||
### Security Requirements (Non-Negotiable)
|
### Security Requirements (Non-Negotiable)
|
||||||
|
|
||||||
**CSRF** — every POST form and API endpoint must verify a CSRF token tied to the session.
|
**CSRF**: every POST form and API endpoint must verify a CSRF token tied to the session.
|
||||||
|
|
||||||
**Rate limiting** — two layers:
|
**Rate limiting**: two layers:
|
||||||
1. nginx: `limit_req_zone` on /api/ (10 req/s, burst 20)
|
1. nginx: `limit_req_zone` on /api/ (10 req/s, burst 20)
|
||||||
2. PHP: per-IP daily counter in SQLite rate_limits table
|
2. PHP: per-IP daily counter in SQLite rate_limits table
|
||||||
|
|
||||||
**reCAPTCHA v3** — on conversion/upload endpoints. Verify server-side via Google API. Cache result in session (verify once per session, not per request).
|
**reCAPTCHA v3**: on conversion/upload endpoints. Verify server-side via Google API. Cache result in session (verify once per session, not per request).
|
||||||
|
|
||||||
**At-rest encryption** — any user-uploaded file must be encrypted before writing to disk. Use `sodium_crypto_secretstream_xchacha20poly1305_*` for files, `sodium_crypto_secretbox` for strings. Key stored in `.env` as `QC_ENCRYPTION_KEY` (32 bytes hex).
|
**At-rest encryption**: any user-uploaded file must be encrypted before writing to disk. Use `sodium_crypto_secretstream_xchacha20poly1305_*` for files, `sodium_crypto_secretbox` for strings. Key stored in `.env` as `QC_ENCRYPTION_KEY` (32 bytes hex).
|
||||||
|
|
||||||
**Signed download tokens** — never expose file paths. Issue a 64-char hex token stored in SQLite with expiry and single-use enforcement.
|
**Signed download tokens**: never expose file paths. Issue a 64-char hex token stored in SQLite with expiry and single-use enforcement.
|
||||||
|
|
||||||
**Magic link auth** — prefer magic link over password. On register: create account unverified, send verify email, block login until verified. Token: 64-char hex, 1-hour expiry, stored in `magic_tokens` table, consumed on use.
|
**Magic link auth**: prefer magic link over password. On register: create account unverified, send verify email, block login until verified. Token: 64-char hex, 1-hour expiry, stored in `magic_tokens` table, consumed on use.
|
||||||
|
|
||||||
### Nginx Security Headers
|
### Nginx Security Headers
|
||||||
|
|
||||||
@@ -1720,7 +1720,7 @@ add_header Referrer-Policy "strict-origin-when-cross-origin" always;
|
|||||||
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
|
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
|
||||||
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' https://www.google.com https://www.gstatic.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; object-src 'none'; base-uri 'self'; form-action 'self' https://checkout.stripe.com;" always;
|
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' https://www.google.com https://www.gstatic.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; object-src 'none'; base-uri 'self'; form-action 'self' https://checkout.stripe.com;" always;
|
||||||
|
|
||||||
# Stripe webhook — POST only
|
# Stripe webhook: POST only
|
||||||
location = /api/stripe-webhook.php {
|
location = /api/stripe-webhook.php {
|
||||||
limit_except POST { deny all; }
|
limit_except POST { deny all; }
|
||||||
}
|
}
|
||||||
@@ -1741,7 +1741,7 @@ catch (Throwable $e) { /* column already exists */ }
|
|||||||
### Stripe Integration
|
### Stripe Integration
|
||||||
|
|
||||||
- Checkout: create session server-side, redirect to Stripe-hosted page
|
- Checkout: create session server-side, redirect to Stripe-hosted page
|
||||||
- Webhook: verify `Stripe-Signature` header using HMAC-SHA256 (implement without Stripe SDK — use curl)
|
- Webhook: verify `Stripe-Signature` header using HMAC-SHA256 (implement without Stripe SDK: use curl)
|
||||||
- Webhook tolerance: 300 seconds (5 min) on timestamp
|
- Webhook tolerance: 300 seconds (5 min) on timestamp
|
||||||
- Register webhook endpoint at: `https://{domain}/api/stripe-webhook.php`
|
- Register webhook endpoint at: `https://{domain}/api/stripe-webhook.php`
|
||||||
- Events to subscribe: `checkout.session.completed`, `customer.subscription.created`, `customer.subscription.updated`, `customer.subscription.deleted`, `invoice.payment_succeeded`, `invoice.payment_failed`
|
- Events to subscribe: `checkout.session.completed`, `customer.subscription.created`, `customer.subscription.updated`, `customer.subscription.deleted`, `invoice.payment_succeeded`, `invoice.payment_failed`
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
# Image Generation Workflow — Arising Media
|
# Image Generation Workflow: Arising Media
|
||||||
|
|
||||||
Last updated: 2026-05-10
|
Last updated: 2026-06-09
|
||||||
Project reference: cobhamtech.com (first full run)
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -15,13 +14,13 @@ Standardized process for generating, validating, and deploying AI images across
|
|||||||
|
|
||||||
API: Google Gemini (generativelanguage.googleapis.com)
|
API: Google Gemini (generativelanguage.googleapis.com)
|
||||||
SDK: google-genai (NOT the deprecated google-generativeai package)
|
SDK: google-genai (NOT the deprecated google-generativeai package)
|
||||||
Draft model: gemini-2.5-flash-image (Nano Banana — Speed Mode)
|
Draft model: gemini-2.5-flash-image (Nano Banana: Speed Mode)
|
||||||
Final model: imagen-4.0-generate-001 (Imagen 4 — Quality Mode)
|
Final model: imagen-4.0-generate-001 (Imagen 4: Quality Mode)
|
||||||
Format: JPEG, 85% quality, max 1600px wide
|
Format: JPEG, 85% quality, max 1600px wide
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Phase 1 — Site Analysis (before any generation)
|
## Phase 1: Site Analysis (before any generation)
|
||||||
|
|
||||||
Before generating images, read:
|
Before generating images, read:
|
||||||
- index.html (home page structure)
|
- index.html (home page structure)
|
||||||
@@ -38,14 +37,14 @@ Document this in: 01-model-selection.md (image plan table)
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Phase 2 — Prompt Engineering
|
## Phase 2: Prompt Engineering
|
||||||
|
|
||||||
### Rules
|
### Rules
|
||||||
- Always reference the site color palette in the prompt (dark navy, slate blue, gold accents)
|
- Always reference the site color palette in the prompt (dark navy, slate blue, gold accents)
|
||||||
- Specify "no text" and "no logos" for background images
|
- Specify "no text" and "no logos" for background images
|
||||||
- Specify "photorealistic" for all marketing images
|
- Specify "photorealistic" for all marketing images
|
||||||
- NO PEOPLE. NO FACES. Hardware, infrastructure, and environment only across all client sites
|
- NO PEOPLE. NO FACES. Hardware, infrastructure, and environment only across all client sites
|
||||||
- This applies to all slots: hero, about, services, contact, location — no exceptions
|
- This applies to all slots: hero, about, services, contact, location: no exceptions
|
||||||
- Reason: faces introduce identity/representation risk and age poorly. Hardware stays neutral and professional.
|
- Reason: faces introduce identity/representation risk and age poorly. Hardware stays neutral and professional.
|
||||||
|
|
||||||
### Prompt structure
|
### Prompt structure
|
||||||
@@ -54,13 +53,13 @@ Document this in: 01-model-selection.md (image plan table)
|
|||||||
### Example (hero background)
|
### Example (hero background)
|
||||||
"Professional enterprise server room, long corridor of dark rack servers with blue LED ambient lighting, deep perspective, dark navy background, cinematic shallow depth of field, no people, photorealistic, ultra detailed"
|
"Professional enterprise server room, long corridor of dark rack servers with blue LED ambient lighting, deep perspective, dark navy background, cinematic shallow depth of field, no people, photorealistic, ultra detailed"
|
||||||
|
|
||||||
### cobhamtech.com brand prompt additions
|
### Per-project brand prompt additions
|
||||||
Always append to prompts for this client:
|
Append brand-specific color and tone language to every prompt for a given client.
|
||||||
"dark navy and blue ambient lighting, professional, enterprise, no text"
|
Example: "dark navy and blue ambient lighting, professional, enterprise, no text"
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Phase 3 — Generation Script Pattern
|
## Phase 3: Generation Script Pattern
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from google import genai
|
from google import genai
|
||||||
@@ -84,16 +83,16 @@ with open('output.jpg', 'wb') as f:
|
|||||||
|
|
||||||
Validate: file must be > 10,000 bytes. Anything smaller is an API error or empty response.
|
Validate: file must be > 10,000 bytes. Anything smaller is an API error or empty response.
|
||||||
|
|
||||||
CRITICAL — Vision validation is mandatory before saving any image:
|
CRITICAL: Vision validation is mandatory before saving any image:
|
||||||
The toolbox script (ai-imagen-generate.sh) automatically sends each generated image to
|
The toolbox script (ai-imagen-generate.sh) automatically sends each generated image to
|
||||||
gemini-2.0-flash for visual inspection. It asks: "Does this image contain people, faces,
|
gemini-2.0-flash for visual inspection. It asks: "Does this image contain people, faces,
|
||||||
hands, silhouettes, or body parts?" If YES — the image is rejected, prompt is tightened,
|
hands, silhouettes, or body parts?" If YES: the image is rejected, prompt is tightened,
|
||||||
and generation retries up to 3 times. Only images that pass inspection are saved.
|
and generation retries up to 3 times. Only images that pass inspection are saved.
|
||||||
Claude cannot visually inspect images — the vision validation step is the enforcement gate.
|
Claude cannot visually inspect images: the vision validation step is the enforcement gate.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Phase 4 — Placement Patterns
|
## Phase 4: Placement Patterns
|
||||||
|
|
||||||
### Pattern A: CSS background-image with dark overlay (hero sections)
|
### Pattern A: CSS background-image with dark overlay (hero sections)
|
||||||
|
|
||||||
@@ -143,15 +142,15 @@ Implementation: add img to existing grid + expand grid columns
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Phase 5 — CSP and nginx Updates
|
## Phase 5: CSP and nginx Updates
|
||||||
|
|
||||||
Any new image source domain requires a CSP update in nginx.conf.
|
Any new image source domain requires a CSP update in nginx.conf.
|
||||||
For Google Maps tiles: add `https://*.googleapis.com https://*.gstatic.com` to `img-src`
|
For Google Maps tiles: add `https://*.googleapis.com https://*.gstatic.com` to `img-src`
|
||||||
For self-hosted images: `img-src 'self' data:` is sufficient — no change needed
|
For self-hosted images: `img-src 'self' data:` is sufficient: no change needed
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Phase 6 — Docker Rebuild and Verify
|
## Phase 6: Docker Rebuild and Verify
|
||||||
|
|
||||||
After every image + HTML change:
|
After every image + HTML change:
|
||||||
|
|
||||||
@@ -192,11 +191,3 @@ Every generation run must produce a log entry in:
|
|||||||
|
|
||||||
Log must include: date, client, model, each image file name, prompt used, file size in bytes, placement pattern used, Docker rebuild result.
|
Log must include: date, client, model, each image file name, prompt used, file size in bytes, placement pattern used, Docker rebuild result.
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Cobhamtech.com Run Reference
|
|
||||||
|
|
||||||
Container: cobhamtech-site
|
|
||||||
Port: 8010
|
|
||||||
Assets path: /home/sirdrez/arisingmedia-websites/cobhamtech.com/assets/images/
|
|
||||||
Color tokens: --ct-black #0c0f18 / --ct-slate #1c2d42 / --ct-blue #2d5a9e / --ct-gold #c79330
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ Source: cutout.pro/model-comparison/imagen-vs-nanobanana + Gemini API model audi
|
|||||||
|
|
||||||
## Available Models (via Google Gemini API)
|
## Available Models (via Google Gemini API)
|
||||||
|
|
||||||
### Imagen 4 — Quality Mode
|
### Imagen 4: Quality Mode
|
||||||
Model ID: `imagen-4.0-generate-001`
|
Model ID: `imagen-4.0-generate-001`
|
||||||
Also available: `imagen-4.0-ultra-generate-001`
|
Also available: `imagen-4.0-ultra-generate-001`
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ Use for:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Nano Banana (Gemini 2.5 Flash Image) — Speed Mode
|
### Nano Banana (Gemini 2.5 Flash Image): Speed Mode
|
||||||
Model ID: `gemini-2.5-flash-image`
|
Model ID: `gemini-2.5-flash-image`
|
||||||
|
|
||||||
Strengths:
|
Strengths:
|
||||||
@@ -40,7 +40,7 @@ Use for:
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### Imagen 4 Fast — Budget Mode
|
### Imagen 4 Fast: Budget Mode
|
||||||
Model ID: `imagen-4.0-fast-generate-001`
|
Model ID: `imagen-4.0-fast-generate-001`
|
||||||
|
|
||||||
Use for:
|
Use for:
|
||||||
@@ -52,38 +52,26 @@ Use for:
|
|||||||
|
|
||||||
## Recommended Workflow
|
## Recommended Workflow
|
||||||
|
|
||||||
Step 1 — Draft with Speed Mode (`gemini-2.5-flash-image`)
|
Step 1: Draft with Speed Mode (`gemini-2.5-flash-image`)
|
||||||
Generate 2-4 variations quickly. Confirm composition, subject, and tone. Low cost.
|
Generate 2-4 variations quickly. Confirm composition, subject, and tone. Low cost.
|
||||||
|
|
||||||
Step 2 — Refine with Quality Mode (`imagen-4.0-generate-001`)
|
Step 2: Refine with Quality Mode (`imagen-4.0-generate-001`)
|
||||||
Take the winning prompt from step 1. Generate final version at full quality.
|
Take the winning prompt from step 1. Generate final version at full quality.
|
||||||
This is the image that goes into the site.
|
This is the image that goes into the site.
|
||||||
|
|
||||||
Step 3 — Review against brand palette
|
Step 3: Review against brand palette
|
||||||
Check that image tones align with site color tokens:
|
Check that image tones align with the project's color tokens from `tokens.css`.
|
||||||
- cobhamtech.com: dark navy (#0c0f18), slate (#1c2d42), blue accent (#2d5a9e), gold (#c79330)
|
All hero images need to work behind dark overlays.
|
||||||
- All hero images need to work behind dark overlays
|
|
||||||
|
|
||||||
Step 4 — Save to project assets
|
Step 4: Save to project assets
|
||||||
Path convention: `assets/images/{page}-{slot}.jpg`
|
Path convention: `assets/images/{page}-{slot}.jpg`
|
||||||
Examples: `hero-bg.jpg`, `about-visual.jpg`, `services-bg.jpg`
|
Examples: `hero-bg.jpg`, `about-visual.jpg`, `services-bg.jpg`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Cobhamtech.com Image Plan
|
|
||||||
|
|
||||||
| Slot | File | Page | Prompt Theme |
|
|
||||||
|------|------|------|--------------|
|
|
||||||
| Hero background | `hero-bg.jpg` | index.html | Dark server room, blue ambient lighting, depth of field |
|
|
||||||
| About story | `about-visual.jpg` | about.html | IT professional at clean desk, dual monitors, neutral dark background |
|
|
||||||
| Services hub | `services-bg.jpg` | services/index.html | Enterprise network infrastructure, abstract, dark |
|
|
||||||
| Intro visual | `intro-visual.jpg` | index.html | Business and technology handshake, professional setting |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
- Never use Nano Banana for final production images on client sites
|
- Never use Nano Banana for final production images on client sites
|
||||||
- Imagen 4 Ultra adds marginal quality gain over standard — not worth the cost for web assets
|
- Imagen 4 Ultra adds marginal quality gain over standard: not worth the cost for web assets
|
||||||
- All images should be exported as JPEG at 85% quality, max 1600px wide, for web performance
|
- All images should be exported as JPEG at 85% quality, max 1600px wide, for web performance
|
||||||
- Run generated images through the site CSP — ensure `img-src` allows `self` and `data:` only (no external CDN hotlinking)
|
- Run generated images through the site CSP: ensure `img-src` allows `self` and `data:` only (no external CDN hotlinking)
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
# Local Image Generation — SOPs
|
# Local Image Generation: SOPs
|
||||||
|
|
||||||
Complete reference for generating site images locally using ComfyUI.
|
Complete reference for generating site images locally using ComfyUI.
|
||||||
No cloud API required. No per-image cost. Runs on the Arising Media workstation.
|
No cloud API required. No per-image cost. Runs on the Arising Media workstation.
|
||||||
|
|
||||||
## Index
|
## Index
|
||||||
|
|
||||||
1. [01-comfyui-setup.md](01-comfyui-setup.md) — Installing ComfyUI, venv, GGUF node
|
1. [01-comfyui-setup.md](01-comfyui-setup.md): Installing ComfyUI, venv, GGUF node
|
||||||
2. [02-flux-images.md](02-flux-images.md) — FLUX.1 Schnell image generation pipeline
|
2. [02-flux-images.md](02-flux-images.md): FLUX.1 Schnell image generation pipeline
|
||||||
3. [03-wan-video.md](03-wan-video.md) — Wan 2.2 image-to-video pipeline
|
3. [03-wan-video.md](03-wan-video.md): Wan 2.2 image-to-video pipeline
|
||||||
4. [04-prompt-guide.md](04-prompt-guide.md) — Prompt patterns for interior/carpet photography
|
4. [04-prompt-guide.md](04-prompt-guide.md): Prompt patterns for interior/carpet photography
|
||||||
5. [05-quality-levers.md](05-quality-levers.md) — Prompt, steps, model size: what to adjust and when
|
5. [05-quality-levers.md](05-quality-levers.md): Prompt, steps, model size: what to adjust and when
|
||||||
|
|
||||||
## Quick start (images already set up)
|
## Quick start (images already set up)
|
||||||
|
|
||||||
@@ -42,5 +42,5 @@ docker compose build --no-cache web && docker compose up -d
|
|||||||
|
|
||||||
## Reference project
|
## Reference project
|
||||||
|
|
||||||
`lahrcarpetcleaning.com` — first project using this full pipeline.
|
`lahrcarpetcleaning.com`: first project using this full pipeline.
|
||||||
Scripts: `tools/gen-images-flux.py`, `tools/gen-video-wan.py`, `tools/convert-to-webp.py`
|
Scripts: `tools/gen-images-flux.py`, `tools/gen-video-wan.py`, `tools/convert-to-webp.py`
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# WP + Divi to AM Stack A Pipeline — SOP Index
|
# WP + Divi to AM Stack A Pipeline: SOP Index
|
||||||
|
|
||||||
End-to-end playbook for converting any WordPress / Divi site backup (.wpress)
|
End-to-end playbook for converting any WordPress / Divi site backup (.wpress)
|
||||||
into an Arising Media Stack A deployment: PHP router + SQLite + vanilla JS/CSS.
|
into an Arising Media Stack A deployment: PHP router + SQLite + vanilla JS/CSS.
|
||||||
@@ -17,23 +17,23 @@ complete ordered execution checklist.
|
|||||||
|
|
||||||
| File | Phase | Description |
|
| File | Phase | Description |
|
||||||
|------|-------|-------------|
|
|------|-------|-------------|
|
||||||
| `00-overview.md` | — | Pipeline overview, philosophy, what to extract vs not replicate |
|
| `00-overview.md` | n/a | Pipeline overview, philosophy, what to extract vs not replicate |
|
||||||
| `01-wpress-extraction.md` | 1 | .wpress binary format, extraction script, verification |
|
| `01-wpress-extraction.md` | 1 | .wpress binary format, extraction script, verification |
|
||||||
| `02-database-analysis.md` | 2 | MySQL dump parsing, page inventory, Divi version detection |
|
| `02-database-analysis.md` | 2 | MySQL dump parsing, page inventory, Divi version detection |
|
||||||
| `03-divi-content-extraction.md` | 3 | Divi 4 shortcodes vs Divi 5 blocks, extraction scripts |
|
| `03-divi-content-extraction.md` | 3 | Divi 4 shortcodes vs Divi 5 blocks, extraction scripts |
|
||||||
| `04-design-system-extraction.md` | 4 | Colors, fonts, spacing → tokens.css |
|
| `04-design-system-extraction.md` | 4 | Colors, fonts, spacing to tokens.css |
|
||||||
| `05-content-migration.md` | 5-6 | Section remapping, content staging, seed_databases.py |
|
| `05-content-migration.md` | 5-6 | Section remapping, content staging, seed_databases.py |
|
||||||
| `06-media-assets.md` | 5 | Upload migration, WebP conversion, media manifest |
|
| `06-media-assets.md` | 5 | Upload migration, WebP conversion, media manifest |
|
||||||
| `07-seo-preservation.md` | 7 | Redirect map, Rank Math extraction, schema.org |
|
| `07-seo-preservation.md` | 7 | Redirect map, Rank Math extraction, schema.org |
|
||||||
| `08-run-order.md` | — | DEPRECATED — superseded by `10-agent-breadcrumbs.md` |
|
| `08-run-order.md` | n/a | DEPRECATED. Superseded by `10-agent-breadcrumbs.md` |
|
||||||
| `09-stack-a-output.md` | — | SQLite schemas, sections_json spec, Divi→AM module mapping |
|
| `09-stack-a-output.md` | n/a | SQLite schemas, sections_json spec, Divi to AM module mapping |
|
||||||
| `10-agent-breadcrumbs.md` | 0-11 | Ordered agent execution checklist (.wpress → live Docker) |
|
| `10-agent-breadcrumbs.md` | 0-11 | Ordered agent execution checklist (.wpress to live Docker) |
|
||||||
|
|
||||||
## Scripts in scripts/
|
## Scripts in scripts/
|
||||||
|
|
||||||
| Script | Purpose |
|
| Script | Purpose |
|
||||||
|--------|---------|
|
|--------|---------|
|
||||||
| `migrate.py` | CLI launcher — runs phases 0-6, prints breadcrumbs for 7-11 |
|
| `migrate.py` | CLI launcher: runs phases 0-6, prints breadcrumbs for 7-11 |
|
||||||
| `run_pipeline.sh` | Legacy shell wrapper (pre-migrate.py) |
|
| `run_pipeline.sh` | Legacy shell wrapper (pre-migrate.py) |
|
||||||
| `extract_wpress.py` | Unpack .wpress binary archive |
|
| `extract_wpress.py` | Unpack .wpress binary archive |
|
||||||
| `analyze_db.py` | Parse SQL dump → pages.json + design-system.json |
|
| `analyze_db.py` | Parse SQL dump → pages.json + design-system.json |
|
||||||
@@ -43,39 +43,13 @@ complete ordered execution checklist.
|
|||||||
|
|
||||||
## Key facts about .wpress archives
|
## Key facts about .wpress archives
|
||||||
|
|
||||||
- Format: Custom sequential binary (NOT zip/tar) — 4377-byte headers
|
- Format: Custom sequential binary (NOT zip/tar): 4377-byte headers
|
||||||
- Table prefix in SQL dump: `SERVMASK_PREFIX_` (placeholder, NOT `wp_`)
|
- Table prefix in SQL dump: `SERVMASK_PREFIX_` (placeholder, NOT `wp_`)
|
||||||
- Directory layout: flat — `uploads/`, `themes/`, `plugins/` at archive root (no `wp-content/` wrapper)
|
- Directory layout: flat: `uploads/`, `themes/`, `plugins/` at archive root (no `wp-content/` wrapper)
|
||||||
- Divi 5 stores theme settings in `et_divi` option as PHP-serialized array
|
- Divi 5 stores theme settings in `et_divi` option as PHP-serialized array
|
||||||
|
|
||||||
## vibrantyou.yoga — extracted data reference
|
|
||||||
|
|
||||||
Site: Vibrant You Yoga (instructor: Meghan)
|
|
||||||
Domain: https://vibrantyou.yoga
|
|
||||||
Divi version: 5.0.3
|
|
||||||
WP version: 6.9.4
|
|
||||||
|
|
||||||
Design system:
|
|
||||||
- Primary: #1a8a7a Dark: #0f5f53 Secondary: #2ea3f2
|
|
||||||
- Body: #5a6b68 Headings: #2d2d2d
|
|
||||||
- Body font: DM Sans 17px / 1.6 lh
|
|
||||||
- Heading font: DM Serif Display 600 / 36px / 1.2 lh
|
|
||||||
|
|
||||||
Pages to migrate (22 published):
|
|
||||||
- home, about, classes, schedule, instructors, contact, blog, faq
|
|
||||||
- book (private sessions), online-yoga, donate
|
|
||||||
- Drop: video-category, video-tag, search-videos, user-videos, player-embed,
|
|
||||||
categories, tags, my-bookings (all plugin-generated archive pages)
|
|
||||||
|
|
||||||
Plugins requiring AM replacements:
|
|
||||||
- Gravity Forms + Stripe → AM HTML form + Python API + Resend
|
|
||||||
- Events Manager → static schedule table in /schedule/
|
|
||||||
- All-in-One Video Gallery → embed YouTube/Vimeo directly or drop
|
|
||||||
|
|
||||||
## Related SOPs
|
## Related SOPs
|
||||||
|
|
||||||
- `../01-project-structure.md` — AM deployment directory layout
|
- `../STACK.md`: AM deployment directory layout, build pipeline, WP migration playbook
|
||||||
- `../02-wordpress-to-html-migration.md` — Original 8-phase WP migration playbook
|
- `../OPTIMIZATION.md`: Full `<head>` requirements, schema.org per page type
|
||||||
- `../03-build-pipeline.md` — JSON + template stamping for repeated pages
|
- `../tools/verify-protection.sh`: Post-deploy security audit
|
||||||
- `../06-seo-meta.md` — Full `<head>` requirements, schema.org per page type
|
|
||||||
- `../tools/verify-protection.sh` — Post-deploy security audit
|
|
||||||
|
|||||||
Reference in New Issue
Block a user