Skip to content

Commit 05c6414

Browse files
committed
fix(seo): crawler metadata, canonical powerback.us, index.html cache docs
- Align meta, og:twitter descriptions and Organization JSON-LD with public copy - Add link rel=canonical for https://powerback.us/ - Document nginx: revalidate index.html; immutable hashed static assets - Cross-link demo-mode nginx caching to production-setup
1 parent ebadf3d commit 05c6414

4 files changed

Lines changed: 146 additions & 116 deletions

File tree

client/public/index.html

Lines changed: 114 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,15 @@
4646
/>
4747
<meta
4848
name="description"
49-
content="Conditional political donation platform that ties campaign contributions to legislative action."
49+
content="POWERBACK lets citizens make political donations conditional on public legislative action, so politicians have to earn support instead of taking it upfront."
5050
/>
5151
<meta
5252
property="og:description"
53-
content="%TAGLINE%"
53+
content="POWERBACK lets citizens make political donations conditional on public legislative action, so politicians have to earn support instead of taking it upfront."
54+
/>
55+
<link
56+
rel="canonical"
57+
href="https://powerback.us/"
5458
/>
5559
<meta
5660
property="og:image"
@@ -102,7 +106,7 @@
102106
/>
103107
<meta
104108
name="twitter:description"
105-
content="%TAGLINE%"
109+
content="POWERBACK lets citizens make political donations conditional on public legislative action, so politicians have to earn support instead of taking it upfront."
106110
/>
107111
<meta
108112
name="twitter:image"
@@ -125,113 +129,113 @@
125129
rel="privacy-policy"
126130
href="/privacy"
127131
/>
128-
<!-- FAQ_SCHEMA_JSONLD_START (auto-generated by scripts/build/build-content.js) -->
129-
<script type="application/ld+json">
130-
{
131-
"@context": "https://schema.org",
132-
"@type": "FAQPage",
133-
"name": "POWERBACK FAQ",
134-
"mainEntity": [
135-
{
136-
"@type": "Question",
137-
"name": "What is POWERBACK.us?",
138-
"acceptedAnswer": {
139-
"@type": "Answer",
140-
"text": "POWERBACK.us (\"POWERBACK\") is a donation platform that gives small-dollar donors real leverage. Instead of giving money directly to campaigns, your donations are kept in a segregated account and only forwarded to the campaign when the conditional rules you agreed to are satisfied. This creates accountability and ensures your money goes to politicians who actually represent your interests."
141-
}
142-
},
143-
{
144-
"@type": "Question",
145-
"name": "Why should I only use POWERBACK for my political contributions, and not other platforms?",
146-
"acceptedAnswer": {
147-
"@type": "Answer",
148-
"text": "POWERBACK is built for voters, not politicians. Your contributions stay in a segregated account until the conditional rules you accepted are met, giving you real leverage. Our first goal is a House floor vote on the \"We The People (https://www.congress.gov/bill/119th-congress/house-joint-resolution/54)\" amendment to overturn Citizens United."
149-
}
150-
},
151-
{
152-
"@type": "Question",
153-
"name": "Why give money to politicians when nothing ever changes, and they may not even get it?",
154-
"acceptedAnswer": {
155-
"@type": "Answer",
156-
"text": "Your donation becomes a public record you can share and organize around. Tag your Representatives and ask why the money's still sitting there. POWERBACK brings the receipts."
157-
}
158-
},
159-
{
160-
"@type": "Question",
161-
"name": "Can I give to challengers through POWERBACK, or only incumbents?",
162-
"acceptedAnswer": {
163-
"@type": "Answer",
164-
"text": "We focus on current office holders to create immediate pressure. Term limits are popular, but fund limits are powerful. If incumbents don't serve the people, that creates opportunities for challengers."
165-
}
166-
},
167-
{
168-
"@type": "Question",
169-
"name": "What is a Celebration?",
170-
"acceptedAnswer": {
171-
"@type": "Answer",
172-
"text": "A Celebration is your conditional donation. POWERBACK keeps it in a segregated account and only delivers it to the campaign if the \"We The People (https://www.congress.gov/bill/119th-congress/house-joint-resolution/54)\" amendment gets a House floor vote. It's tied to the vote happening, not any individual lawmaker's actions."
173-
}
174-
},
175-
{
176-
"@type": "Question",
177-
"name": "What if a vote on We The People never happens? Do I get a refund?",
178-
"acceptedAnswer": {
179-
"@type": "Answer",
180-
"text": "No. Refunds would erase the stakes. Although Celebrations are irreversible, if they fail, your donation goes to support POWERBACK as a fallback so we can maintain the platform and expand it beyond one bill, while refusing to reward political hypocrisy and inaction."
181-
}
182-
},
183-
{
184-
"@type": "Question",
185-
"name": "Why isn't my Representative/State listed?",
186-
"acceptedAnswer": {
187-
"@type": "Answer",
188-
"text": "We only list Representatives that are facing serious, financed challengers to their seat according to campaign filings with the Federal Election Commission. In other words, your Representative is virtually unopposed this election. Run against them!"
189-
}
190-
},
191-
{
192-
"@type": "Question",
193-
"name": "Does POWERBACK cover any other bills, or the Senate, or local elections?",
194-
"acceptedAnswer": {
195-
"@type": "Answer",
196-
"text": "Right now, we only focus on \"We The People (https://www.congress.gov/bill/119th-congress/house-joint-resolution/54).\" We're working to expand to other bills and elections. Want to help? Become a patron (https://www.patreon.com/powerback) or join our Discord (https://powerback.us/discord) to stay updated."
197-
}
198-
},
199-
{
200-
"@type": "Question",
201-
"name": "What does POWERBACK charge?",
202-
"acceptedAnswer": {
203-
"@type": "Answer",
204-
"text": "2.9% plus 30 cents per Celebration (Stripe's fee). Other platforms charge 3.95% flat, which is cheaper for small donations under $29. Above that, we're cheaper. We keep the lights on while keeping your donations impactful."
205-
}
206-
},
207-
{
208-
"@type": "Question",
209-
"name": "Does POWERBACK have any party or corporate affiliation?",
210-
"acceptedAnswer": {
211-
"@type": "Answer",
212-
"text": "No. We're independent and open source. Candidate order is randomized, and we never mention political parties. Check out our code on GitHub (https://github.com/powerbackus/powerback), follow us on X (https://x.com/PowerbackApp), join Discord (https://powerback.us/discord), or read our position paper (/position-paper.pdf) for details."
213-
}
214-
},
215-
{
216-
"@type": "Question",
217-
"name": "Will campaigns email me?",
218-
"acceptedAnswer": {
219-
"@type": "Answer",
220-
"text": "We don't provide your email address to candidate campaigns, so you won't get added to their mailing lists through POWERBACK."
221-
}
222-
},
223-
{
224-
"@type": "Question",
225-
"name": "Is POWERBACK a prediction or event market?",
226-
"acceptedAnswer": {
227-
"@type": "Answer",
228-
"text": "No. POWERBACK is an election campaign donation conduit, not a market. We don't offer trading, odds, shares, or payouts based on events. POWERBACK is operated by a federally registered political committee (PAC). Delivery of funds to campaigns and FEC filing are handled manually by the PAC operator; contributions remain in a segregated account under those conditional rules until disposition, and the app provides data for reporting."
229-
}
132+
<!-- FAQ_SCHEMA_JSONLD_START (auto-generated by scripts/build/build-content.js) -->
133+
<script type="application/ld+json">
134+
{
135+
"@context": "https://schema.org",
136+
"@type": "FAQPage",
137+
"name": "POWERBACK FAQ",
138+
"mainEntity": [
139+
{
140+
"@type": "Question",
141+
"name": "What is POWERBACK.us?",
142+
"acceptedAnswer": {
143+
"@type": "Answer",
144+
"text": "POWERBACK.us (\"POWERBACK\") is a donation platform that gives small-dollar donors real leverage. Instead of giving money directly to campaigns, your donations are kept in a segregated account and only forwarded to the campaign when the conditional rules you agreed to are satisfied. This creates accountability and ensures your money goes to politicians who actually represent your interests."
230145
}
231-
]
232-
}
233-
</script>
234-
<!-- FAQ_SCHEMA_JSONLD_END -->
146+
},
147+
{
148+
"@type": "Question",
149+
"name": "Why should I only use POWERBACK for my political contributions, and not other platforms?",
150+
"acceptedAnswer": {
151+
"@type": "Answer",
152+
"text": "POWERBACK is built for voters, not politicians. Your contributions stay in a segregated account until the conditional rules you accepted are met, giving you real leverage. Our first goal is a House floor vote on the \"We The People (https://www.congress.gov/bill/119th-congress/house-joint-resolution/54)\" amendment to overturn Citizens United."
153+
}
154+
},
155+
{
156+
"@type": "Question",
157+
"name": "Why give money to politicians when nothing ever changes, and they may not even get it?",
158+
"acceptedAnswer": {
159+
"@type": "Answer",
160+
"text": "Your donation becomes a public record you can share and organize around. Tag your Representatives and ask why the money's still sitting there. POWERBACK brings the receipts."
161+
}
162+
},
163+
{
164+
"@type": "Question",
165+
"name": "Can I give to challengers through POWERBACK, or only incumbents?",
166+
"acceptedAnswer": {
167+
"@type": "Answer",
168+
"text": "We focus on current office holders to create immediate pressure. Term limits are popular, but fund limits are powerful. If incumbents don't serve the people, that creates opportunities for challengers."
169+
}
170+
},
171+
{
172+
"@type": "Question",
173+
"name": "What is a Celebration?",
174+
"acceptedAnswer": {
175+
"@type": "Answer",
176+
"text": "A Celebration is your conditional donation. POWERBACK keeps it in a segregated account and only delivers it to the campaign if the \"We The People (https://www.congress.gov/bill/119th-congress/house-joint-resolution/54)\" amendment gets a House floor vote. It's tied to the vote happening, not any individual lawmaker's actions."
177+
}
178+
},
179+
{
180+
"@type": "Question",
181+
"name": "What if a vote on We The People never happens? Do I get a refund?",
182+
"acceptedAnswer": {
183+
"@type": "Answer",
184+
"text": "No. Refunds would erase the stakes. Although Celebrations are irreversible, if they fail, your donation goes to support POWERBACK as a fallback so we can maintain the platform and expand it beyond one bill, while refusing to reward political hypocrisy and inaction."
185+
}
186+
},
187+
{
188+
"@type": "Question",
189+
"name": "Why isn't my Representative/State listed?",
190+
"acceptedAnswer": {
191+
"@type": "Answer",
192+
"text": "We only list Representatives that are facing serious, financed challengers to their seat according to campaign filings with the Federal Election Commission. In other words, your Representative is virtually unopposed this election. Run against them!"
193+
}
194+
},
195+
{
196+
"@type": "Question",
197+
"name": "Does POWERBACK cover any other bills, or the Senate, or local elections?",
198+
"acceptedAnswer": {
199+
"@type": "Answer",
200+
"text": "Right now, we only focus on \"We The People (https://www.congress.gov/bill/119th-congress/house-joint-resolution/54).\" We're working to expand to other bills and elections. Want to help? Become a patron (https://www.patreon.com/powerback) or join our Discord (https://powerback.us/discord) to stay updated."
201+
}
202+
},
203+
{
204+
"@type": "Question",
205+
"name": "What does POWERBACK charge?",
206+
"acceptedAnswer": {
207+
"@type": "Answer",
208+
"text": "2.9% plus 30 cents per Celebration (Stripe's fee). Other platforms charge 3.95% flat, which is cheaper for small donations under $29. Above that, we're cheaper. We keep the lights on while keeping your donations impactful."
209+
}
210+
},
211+
{
212+
"@type": "Question",
213+
"name": "Does POWERBACK have any party or corporate affiliation?",
214+
"acceptedAnswer": {
215+
"@type": "Answer",
216+
"text": "No. We're independent and open source. Candidate order is randomized, and we never mention political parties. Check out our code on GitHub (https://github.com/powerbackus/powerback), follow us on X (https://x.com/PowerbackApp), join Discord (https://powerback.us/discord), or read our position paper (/position-paper.pdf) for details."
217+
}
218+
},
219+
{
220+
"@type": "Question",
221+
"name": "Will campaigns email me?",
222+
"acceptedAnswer": {
223+
"@type": "Answer",
224+
"text": "We don't provide your email address to candidate campaigns, so you won't get added to their mailing lists through POWERBACK."
225+
}
226+
},
227+
{
228+
"@type": "Question",
229+
"name": "Is POWERBACK a prediction or event market?",
230+
"acceptedAnswer": {
231+
"@type": "Answer",
232+
"text": "No. POWERBACK is an election campaign donation conduit, not a market. We don't offer trading, odds, shares, or payouts based on events. POWERBACK is operated by a federally registered political committee (PAC). Delivery of funds to campaigns and FEC filing are handled manually by the PAC operator; contributions remain in a segregated account under those conditional rules until disposition, and the app provides data for reporting."
233+
}
234+
}
235+
]
236+
}
237+
</script>
238+
<!-- FAQ_SCHEMA_JSONLD_END -->
235239
<script type="application/ld+json">
236240
{
237241
"@context": "https://schema.org",
@@ -240,7 +244,7 @@
240244
"alternateName": "POWERBACK.us",
241245
"url": "https://powerback.us",
242246
"logo": "https://powerback.us/logo512.png",
243-
"description": "Conditional political donation platform that ties campaign contributions to legislative action.",
247+
"description": "POWERBACK lets citizens make political donations conditional on public legislative action, so politicians have to earn support instead of taking it upfront.",
244248
"sameAs": [
245249
"https://x.com/PowerbackApp",
246250
"https://powerback.us/discord",

docs/demo-mode.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ Or use an A record pointing to the same IP address.
7777

7878
The web server (NGINX or equivalent) must serve the same static build and proxy `/api` to the Node backend for both the main site and the demo hostname.
7979

80+
Use the same **`location = /index.html`** (revalidate) and **hashed static asset** `Cache-Control` patterns as in [Production Setup](./production-setup.md#nginx-configuration) so demo and prod behave consistently after deploys.
81+
8082
**Important:** In NGINX, each `server { }` block has its own set of `location` directives. If you use a **separate** server block for `demo.powerback.us` (e.g. with its own `server_name demo.powerback.us`), that block must include its own `location /api` proxy. Requests to `https://demo.powerback.us/api/...` will not use the main site's `location /api`; without a matching location, they fall through to `location /` and `try_files` serves `index.html`, so the API returns HTML and the app (e.g. PolCarousel) fails.
8183

8284
**Option A – Single server block (all hostnames share config):**

docs/production-setup.md

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -237,15 +237,19 @@ server {
237237
try_files $uri $uri/ /index.html;
238238
}
239239
240+
# SPA shell: revalidate on every request so deploys pick up new index.html
241+
location = /index.html {
242+
add_header Cache-Control "no-cache, must-revalidate" always;
243+
}
244+
240245
# React SPA default
241246
location / {
242247
try_files $uri $uri/ /index.html;
243248
}
244249
245-
# Optional: cache immutable static assets
250+
# Hashed and other static assets: long cache (CRA/Vite emit content-hashed JS/CSS)
246251
location ~* \.(js|css|png|webp|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
247-
expires 1y;
248-
add_header Cache-Control "public, immutable";
252+
add_header Cache-Control "public, max-age=31536000, immutable" always;
249253
}
250254
251255
}
@@ -264,6 +268,22 @@ sudo nginx -t
264268
sudo systemctl reload nginx
265269
```
266270

271+
### 3. Verify HTML metadata and cache headers (post-deploy)
272+
273+
After nginx reload and a client deploy, confirm crawlers and browsers see the intended HTML and `Cache-Control` values.
274+
275+
```bash
276+
curl -fsSL https://powerback.us/ | grep -E 'name="description"|property="og:description"|name="twitter:description"|rel="canonical"'
277+
278+
curl -sI https://powerback.us/ | grep -i '^cache-control:'
279+
280+
HASHED_JS=$(curl -fsSL https://powerback.us/ | grep -oE '/static/js/[^"]+\.js' | head -n1)
281+
curl -sI "https://powerback.us${HASHED_JS}" | grep -i '^cache-control:'
282+
283+
HASHED_CSS=$(curl -fsSL https://powerback.us/ | grep -oE '/static/css/[^"]+\.css' | head -n1)
284+
curl -sI "https://powerback.us${HASHED_CSS}" | grep -i '^cache-control:'
285+
```
286+
267287
## Email Configuration
268288

269289
### 1. Email Environment Variables

docs/server-hardening.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -371,15 +371,19 @@ server {
371371
try_files $uri $uri/ /index.html;
372372
}
373373
374+
# SPA shell: revalidate on every request so deploys pick up new index.html
375+
location = /index.html {
376+
add_header Cache-Control "no-cache, must-revalidate" always;
377+
}
378+
374379
# React SPA default
375380
location / {
376381
try_files $uri $uri/ /index.html;
377382
}
378383
379-
# Optional: cache immutable static assets
384+
# Hashed and other static assets: long cache (CRA/Vite emit content-hashed JS/CSS)
380385
location ~* \.(js|css|png|webp|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
381-
expires 1y;
382-
add_header Cache-Control "public, immutable";
386+
add_header Cache-Control "public, max-age=31536000, immutable" always;
383387
}
384388
385389
}

0 commit comments

Comments
 (0)