@undp/create-app 0.91.0 → 0.91.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (25) hide show
  1. package/README.md +5 -3
  2. package/bin/generateFiles/generateIndexHtml.js +13 -5
  3. package/bin/generateFiles/generatePackageJson.js +1 -0
  4. package/bin/generateFiles/generateStaticWebAppConfig.js +15 -5
  5. package/bin/generateFiles/generateViteConfig.js +6 -0
  6. package/bin/promptUser.js +146 -127
  7. package/bin/templates/next/auth/README.md +17 -0
  8. package/bin/templates/next/basic/README.md +17 -0
  9. package/bin/templates/vite/basic/.github/ISSUE_TEMPLATE/launch-checklist.md +73 -0
  10. package/bin/templates/vite/basic/README.md +40 -5
  11. package/bin/templates/vite/query/.github/ISSUE_TEMPLATE/launch-checklist.md +73 -0
  12. package/bin/templates/vite/query/README.md +39 -5
  13. package/bin/templates/vite/query+router/.github/ISSUE_TEMPLATE/launch-checklist.md +73 -0
  14. package/bin/templates/vite/query+router/README.md +17 -0
  15. package/bin/templates/vite/router/.github/ISSUE_TEMPLATE/launch-checklist.md +73 -0
  16. package/bin/templates/vite/router/README.md +17 -0
  17. package/bin/templates/viteWithLanguage/basic/.github/ISSUE_TEMPLATE/launch-checklist.md +73 -0
  18. package/bin/templates/viteWithLanguage/basic/README.md +52 -5
  19. package/bin/templates/viteWithLanguage/query/.github/ISSUE_TEMPLATE/launch-checklist.md +73 -0
  20. package/bin/templates/viteWithLanguage/query/README.md +53 -5
  21. package/bin/templates/viteWithLanguage/query+router/.github/ISSUE_TEMPLATE/launch-checklist.md +72 -0
  22. package/bin/templates/viteWithLanguage/query+router/README.md +17 -0
  23. package/bin/templates/viteWithLanguage/router/.github/ISSUE_TEMPLATE/launch-checklist.md +73 -0
  24. package/bin/templates/viteWithLanguage/router/README.md +17 -0
  25. package/package.json +1 -1
@@ -0,0 +1,73 @@
1
+ ---
2
+ name: Launch checklist
3
+ about: Pre-launch checks to complete before going to production
4
+ title: "Launch checklist"
5
+ labels: launch
6
+ assignees: ''
7
+ ---
8
+
9
+ <!-- Tick items as you go. Don't close this issue until every box is checked or explicitly marked N/A with a reason. -->
10
+
11
+ ## Metadata & SEO
12
+
13
+ - [ ] Favicon added (`favicon.ico` + SVG).
14
+ - [ ] `<meta name="theme-color">` added.
15
+ - [ ] `<html lang="…">` is set correctly.
16
+ - [ ] Every route has a unique `<title>` and `<meta name="description">`.
17
+ - [ ] Every route has a canonical URL: `<link rel="canonical" href="…">`.
18
+ - [ ] Open Graph and Twitter tags are added (globally in `index.html` or per route). Use absolute URLs for `og:url` and `og:image`:
19
+
20
+ ```html
21
+ <meta property="og:type" content="website" />
22
+ <meta property="og:site_name" content="SITE_NAME" />
23
+ <meta property="og:title" content="TITLE" />
24
+ <meta property="og:description" content="DESCRIPTION" />
25
+ <meta property="og:url" content="https://example.com/page" />
26
+ <meta property="og:image" content="https://example.com/og-image.png" />
27
+ <meta property="og:image:width" content="1200" />
28
+ <meta property="og:image:height" content="630" />
29
+ <meta property="og:image:alt" content="IMAGE_ALT_TEXT" />
30
+ <meta name="twitter:card" content="summary_large_image" />
31
+ ```
32
+
33
+ - [ ] Social previews verified with a preview tool (e.g. opengraph.xyz, LinkedIn Post Inspector).
34
+ - [ ] `robots.txt` and `sitemap.xml` are in place.
35
+ - [ ] `<meta name="robots" content="noindex">` is added to routes that should not be indexed for search.
36
+ - [ ] Production is indexable (no leftover `noindex`), and staging is **not** indexable.
37
+ - [ ] `apple-touch-icon` (180×180) added - only needed for site which the users might "install".
38
+ - [ ] `site.webmanifest` added - only needed for site which the users might "install".
39
+
40
+ ## Functionality & QA
41
+
42
+ - [ ] All routes load, including on direct visit or refresh (host has SPA fallback routing).
43
+ - [ ] A custom 404 page exists, and React error boundaries catch runtime errors.
44
+ - [ ] No errors or warnings in the browser console.
45
+ - [ ] All forms, links and external integrations work in production.
46
+ - [ ] Design QA is complete and signed off.
47
+ - [ ] The layout works on all viewport widths from 360px up. At minimum, check 360, 768, 1024 and 1440px.
48
+ - [ ] Tested in the latest Chrome, Firefox, Edge and Safari.
49
+
50
+ ## Performance
51
+
52
+ - [ ] Initial JS on first page load is ≤ 175 KB gzipped.
53
+ - [ ] Main CSS file is ≤ 50 KB gzipped.
54
+ - [ ] Images are optimised (WebP/AVIF, correctly sized, ≤ 75 KB each, lazy-loaded below the fold).
55
+ - [ ] Fonts are subset and preloaded, with `font-display: swap`.
56
+ - [ ] Lighthouse scores (run in incognito against production):
57
+
58
+ | Category | Desktop | Mobile |
59
+ |----------------|---------|--------|
60
+ | Performance | ≥ 90 | ≥ 70 |
61
+ | Accessibility | ≥ 90 | ≥ 90 |
62
+ | Best Practices | ≥ 90 | ≥ 90 |
63
+ | SEO | ≥ 90 | ≥ 90 |
64
+
65
+ ## Security & infrastructure
66
+
67
+ - [ ] `npm audit` shows no high or critical vulnerabilities.
68
+ - [ ] `npm audit --omit=dev` shows no vulnerabilities.
69
+ - [ ] No secrets or private API keys in the client bundle.
70
+
71
+ ## Analytics & privacy
72
+
73
+ - [ ] Google Analytics and/or Microsoft Clarity are installed and events are confirmed arriving from production.
@@ -59,7 +59,9 @@ Data fetching is powered by [TanStack Query](https://tanstack.com/query) for eff
59
59
 
60
60
  To embed the visualization on an external page, include:
61
61
 
62
- **HTML Placeholder**
62
+ ### Option 1: Iframe
63
+
64
+ __HTML Placeholder__
63
65
 
64
66
  ```html
65
67
  <iframe
@@ -70,16 +72,15 @@ To embed the visualization on an external page, include:
70
72
  />
71
73
  ```
72
74
 
73
- **Required `<script>`**
75
+ __Required `<script>`__
74
76
 
75
- ```
77
+ ```js
76
78
  <script>
77
79
  var iframe = document.getElementById('my-embed');
78
80
  window.addEventListener('message', function (e) {
79
- if (e.origin !== 'http://localhost:5173') return;
81
+ if (e.origin !== 'APP_URL') return;
80
82
  if (e.source !== iframe.contentWindow) return;
81
83
  if (e.data && e.data.type === 'iframe-height') {
82
- console.log('new height', e.data.height);
83
84
  iframe.style.height = e.data.height + 'px';
84
85
  }
85
86
  });
@@ -88,6 +89,39 @@ To embed the visualization on an external page, include:
88
89
 
89
90
  _This script listens for height messages from the embedded web app and resizes the iframe to match its content, so the app displays without an inner scrollbar._
90
91
 
92
+ ### Option 2: Embed in the page (Worst performance better UX)
93
+
94
+ __HTML Placeholder__
95
+
96
+ ```html
97
+ <div id="root"></div>
98
+ ```
99
+
100
+ __Required `<script>` and `<link>` tags__
101
+
102
+ ```html
103
+ <link rel="dns-prefetch" href="{{Visualization URL}}">
104
+ <script defer="defer" type="module" src="{{Visualization URL}}/index.js"></script>
105
+ <link rel="stylesheet" href="{{Visualization URL}}/style.css"></link>
106
+ ```
107
+
108
+ ## ✅ Launch Checklist
109
+
110
+ Before deploying to production, complete the launch checklist. It covers metadata and SEO, analytics, QA, accessibility, performance, security headers and caching.
111
+
112
+ The checklist is set up as a GitHub issue template, so each launch gets its own tickable copy:
113
+
114
+ 1. Go to **Issues → New issue** in this repository.
115
+ 2. Select **Launch checklist**.
116
+ 3. Assign yourself, and click **Create**.
117
+ 4. Tick items off as you complete them. The issue list shows progress (e.g. "7 of 32 tasks").
118
+
119
+ Or open it directly: [Create launch checklist issue](../../issues/new?template=launch-checklist.md)
120
+
121
+ Don't close the issue until every item is checked, or marked N/A with a reason.
122
+
123
+ The template lives in `.github/ISSUE_TEMPLATE/launch-checklist.md`.
124
+
91
125
  ## 📬 Contact us
92
126
 
93
127
  For questions or feedback, contact us at [data@undp.org](mailto:data@undp.org).
@@ -0,0 +1,73 @@
1
+ ---
2
+ name: Launch checklist
3
+ about: Pre-launch checks to complete before going to production
4
+ title: "Launch checklist"
5
+ labels: launch
6
+ assignees: ''
7
+ ---
8
+
9
+ <!-- Tick items as you go. Don't close this issue until every box is checked or explicitly marked N/A with a reason. -->
10
+
11
+ ## Metadata & SEO
12
+
13
+ - [ ] Favicon added (`favicon.ico` + SVG).
14
+ - [ ] `<meta name="theme-color">` added.
15
+ - [ ] `<html lang="…">` is set correctly.
16
+ - [ ] Every route has a unique `<title>` and `<meta name="description">`.
17
+ - [ ] Every route has a canonical URL: `<link rel="canonical" href="…">`.
18
+ - [ ] Open Graph and Twitter tags are added (globally in `index.html` or per route). Use absolute URLs for `og:url` and `og:image`:
19
+
20
+ ```html
21
+ <meta property="og:type" content="website" />
22
+ <meta property="og:site_name" content="SITE_NAME" />
23
+ <meta property="og:title" content="TITLE" />
24
+ <meta property="og:description" content="DESCRIPTION" />
25
+ <meta property="og:url" content="https://example.com/page" />
26
+ <meta property="og:image" content="https://example.com/og-image.png" />
27
+ <meta property="og:image:width" content="1200" />
28
+ <meta property="og:image:height" content="630" />
29
+ <meta property="og:image:alt" content="IMAGE_ALT_TEXT" />
30
+ <meta name="twitter:card" content="summary_large_image" />
31
+ ```
32
+
33
+ - [ ] Social previews verified with a preview tool (e.g. opengraph.xyz, LinkedIn Post Inspector).
34
+ - [ ] `robots.txt` and `sitemap.xml` are in place.
35
+ - [ ] `<meta name="robots" content="noindex">` is added to routes that should not be indexed for search.
36
+ - [ ] Production is indexable (no leftover `noindex`), and staging is **not** indexable.
37
+ - [ ] `apple-touch-icon` (180×180) added - only needed for site which the users might "install".
38
+ - [ ] `site.webmanifest` added - only needed for site which the users might "install".
39
+
40
+ ## Functionality & QA
41
+
42
+ - [ ] All routes load, including on direct visit or refresh (host has SPA fallback routing).
43
+ - [ ] A custom 404 page exists, and React error boundaries catch runtime errors.
44
+ - [ ] No errors or warnings in the browser console.
45
+ - [ ] All forms, links and external integrations work in production.
46
+ - [ ] Design QA is complete and signed off.
47
+ - [ ] The layout works on all viewport widths from 360px up. At minimum, check 360, 768, 1024 and 1440px.
48
+ - [ ] Tested in the latest Chrome, Firefox, Edge and Safari.
49
+
50
+ ## Performance
51
+
52
+ - [ ] Initial JS on first page load is ≤ 175 KB gzipped.
53
+ - [ ] Main CSS file is ≤ 50 KB gzipped.
54
+ - [ ] Images are optimised (WebP/AVIF, correctly sized, ≤ 75 KB each, lazy-loaded below the fold).
55
+ - [ ] Fonts are subset and preloaded, with `font-display: swap`.
56
+ - [ ] Lighthouse scores (run in incognito against production):
57
+
58
+ | Category | Desktop | Mobile |
59
+ |----------------|---------|--------|
60
+ | Performance | ≥ 90 | ≥ 70 |
61
+ | Accessibility | ≥ 90 | ≥ 90 |
62
+ | Best Practices | ≥ 90 | ≥ 90 |
63
+ | SEO | ≥ 90 | ≥ 90 |
64
+
65
+ ## Security & infrastructure
66
+
67
+ - [ ] `npm audit` shows no high or critical vulnerabilities.
68
+ - [ ] `npm audit --omit=dev` shows no vulnerabilities.
69
+ - [ ] No secrets or private API keys in the client bundle.
70
+
71
+ ## Analytics & privacy
72
+
73
+ - [ ] Google Analytics and/or Microsoft Clarity are installed and events are confirmed arriving from production.
@@ -106,6 +106,23 @@ More info: [Link documentation](https://tanstack.com/router/v1/docs/framework/re
106
106
 
107
107
  Data fetching is powered by [TanStack Query](https://tanstack.com/query) for efficient, declarative data fetching and caching.
108
108
 
109
+ ## ✅ Launch Checklist
110
+
111
+ Before deploying to production, complete the launch checklist. It covers metadata and SEO, analytics, QA, accessibility, performance, security headers and caching.
112
+
113
+ The checklist is set up as a GitHub issue template, so each launch gets its own tickable copy:
114
+
115
+ 1. Go to **Issues → New issue** in this repository.
116
+ 2. Select **Launch checklist**.
117
+ 3. Assign yourself, and click **Create**.
118
+ 4. Tick items off as you complete them. The issue list shows progress (e.g. "7 of 32 tasks").
119
+
120
+ Or open it directly: [Create launch checklist issue](../../issues/new?template=launch-checklist.md)
121
+
122
+ Don't close the issue until every item is checked, or marked N/A with a reason.
123
+
124
+ The template lives in `.github/ISSUE_TEMPLATE/launch-checklist.md`.
125
+
109
126
  ## 📬 Contact us
110
127
 
111
128
  For questions or feedback, contact us at [data@undp.org](mailto:data@undp.org).
@@ -0,0 +1,73 @@
1
+ ---
2
+ name: Launch checklist
3
+ about: Pre-launch checks to complete before going to production
4
+ title: "Launch checklist"
5
+ labels: launch
6
+ assignees: ''
7
+ ---
8
+
9
+ <!-- Tick items as you go. Don't close this issue until every box is checked or explicitly marked N/A with a reason. -->
10
+
11
+ ## Metadata & SEO
12
+
13
+ - [ ] Favicon added (`favicon.ico` + SVG).
14
+ - [ ] `<meta name="theme-color">` added.
15
+ - [ ] `<html lang="…">` is set correctly.
16
+ - [ ] Every route has a unique `<title>` and `<meta name="description">`.
17
+ - [ ] Every route has a canonical URL: `<link rel="canonical" href="…">`.
18
+ - [ ] Open Graph and Twitter tags are added (globally in `index.html` or per route). Use absolute URLs for `og:url` and `og:image`:
19
+
20
+ ```html
21
+ <meta property="og:type" content="website" />
22
+ <meta property="og:site_name" content="SITE_NAME" />
23
+ <meta property="og:title" content="TITLE" />
24
+ <meta property="og:description" content="DESCRIPTION" />
25
+ <meta property="og:url" content="https://example.com/page" />
26
+ <meta property="og:image" content="https://example.com/og-image.png" />
27
+ <meta property="og:image:width" content="1200" />
28
+ <meta property="og:image:height" content="630" />
29
+ <meta property="og:image:alt" content="IMAGE_ALT_TEXT" />
30
+ <meta name="twitter:card" content="summary_large_image" />
31
+ ```
32
+
33
+ - [ ] Social previews verified with a preview tool (e.g. opengraph.xyz, LinkedIn Post Inspector).
34
+ - [ ] `robots.txt` and `sitemap.xml` are in place.
35
+ - [ ] `<meta name="robots" content="noindex">` is added to routes that should not be indexed for search.
36
+ - [ ] Production is indexable (no leftover `noindex`), and staging is **not** indexable.
37
+ - [ ] `apple-touch-icon` (180×180) added - only needed for site which the users might "install".
38
+ - [ ] `site.webmanifest` added - only needed for site which the users might "install".
39
+
40
+ ## Functionality & QA
41
+
42
+ - [ ] All routes load, including on direct visit or refresh (host has SPA fallback routing).
43
+ - [ ] A custom 404 page exists, and React error boundaries catch runtime errors.
44
+ - [ ] No errors or warnings in the browser console.
45
+ - [ ] All forms, links and external integrations work in production.
46
+ - [ ] Design QA is complete and signed off.
47
+ - [ ] The layout works on all viewport widths from 360px up. At minimum, check 360, 768, 1024 and 1440px.
48
+ - [ ] Tested in the latest Chrome, Firefox, Edge and Safari.
49
+
50
+ ## Performance
51
+
52
+ - [ ] Initial JS on first page load is ≤ 175 KB gzipped.
53
+ - [ ] Main CSS file is ≤ 50 KB gzipped.
54
+ - [ ] Images are optimised (WebP/AVIF, correctly sized, ≤ 75 KB each, lazy-loaded below the fold).
55
+ - [ ] Fonts are subset and preloaded, with `font-display: swap`.
56
+ - [ ] Lighthouse scores (run in incognito against production):
57
+
58
+ | Category | Desktop | Mobile |
59
+ |----------------|---------|--------|
60
+ | Performance | ≥ 90 | ≥ 70 |
61
+ | Accessibility | ≥ 90 | ≥ 90 |
62
+ | Best Practices | ≥ 90 | ≥ 90 |
63
+ | SEO | ≥ 90 | ≥ 90 |
64
+
65
+ ## Security & infrastructure
66
+
67
+ - [ ] `npm audit` shows no high or critical vulnerabilities.
68
+ - [ ] `npm audit --omit=dev` shows no vulnerabilities.
69
+ - [ ] No secrets or private API keys in the client bundle.
70
+
71
+ ## Analytics & privacy
72
+
73
+ - [ ] Google Analytics and/or Microsoft Clarity are installed and events are confirmed arriving from production.
@@ -101,6 +101,23 @@ import { Link } from "@tanstack/react-router";
101
101
 
102
102
  More info: [Link documentation](https://tanstack.com/router/v1/docs/framework/react/api/router/linkComponent).
103
103
 
104
+ ## ✅ Launch Checklist
105
+
106
+ Before deploying to production, complete the launch checklist. It covers metadata and SEO, analytics, QA, accessibility, performance, security headers and caching.
107
+
108
+ The checklist is set up as a GitHub issue template, so each launch gets its own tickable copy:
109
+
110
+ 1. Go to **Issues → New issue** in this repository.
111
+ 2. Select **Launch checklist**.
112
+ 3. Assign yourself, and click **Create**.
113
+ 4. Tick items off as you complete them. The issue list shows progress (e.g. "7 of 32 tasks").
114
+
115
+ Or open it directly: [Create launch checklist issue](../../issues/new?template=launch-checklist.md)
116
+
117
+ Don't close the issue until every item is checked, or marked N/A with a reason.
118
+
119
+ The template lives in `.github/ISSUE_TEMPLATE/launch-checklist.md`.
120
+
104
121
  ## 📬 Contact us
105
122
 
106
123
  For questions or feedback, contact us at [data@undp.org](mailto:data@undp.org).
@@ -0,0 +1,73 @@
1
+ ---
2
+ name: Launch checklist
3
+ about: Pre-launch checks to complete before going to production
4
+ title: "Launch checklist"
5
+ labels: launch
6
+ assignees: ''
7
+ ---
8
+
9
+ <!-- Tick items as you go. Don't close this issue until every box is checked or explicitly marked N/A with a reason. -->
10
+
11
+ ## Metadata & SEO
12
+
13
+ - [ ] Favicon added (`favicon.ico` + SVG).
14
+ - [ ] `<meta name="theme-color">` added.
15
+ - [ ] `<html lang="…">` is set correctly.
16
+ - [ ] Every route has a unique `<title>` and `<meta name="description">`.
17
+ - [ ] Every route has a canonical URL: `<link rel="canonical" href="…">`.
18
+ - [ ] Open Graph and Twitter tags are added (globally in `index.html` or per route). Use absolute URLs for `og:url` and `og:image`:
19
+
20
+ ```html
21
+ <meta property="og:type" content="website" />
22
+ <meta property="og:site_name" content="SITE_NAME" />
23
+ <meta property="og:title" content="TITLE" />
24
+ <meta property="og:description" content="DESCRIPTION" />
25
+ <meta property="og:url" content="https://example.com/page" />
26
+ <meta property="og:image" content="https://example.com/og-image.png" />
27
+ <meta property="og:image:width" content="1200" />
28
+ <meta property="og:image:height" content="630" />
29
+ <meta property="og:image:alt" content="IMAGE_ALT_TEXT" />
30
+ <meta name="twitter:card" content="summary_large_image" />
31
+ ```
32
+
33
+ - [ ] Social previews verified with a preview tool (e.g. opengraph.xyz, LinkedIn Post Inspector).
34
+ - [ ] `robots.txt` and `sitemap.xml` are in place.
35
+ - [ ] `<meta name="robots" content="noindex">` is added to routes that should not be indexed for search.
36
+ - [ ] Production is indexable (no leftover `noindex`), and staging is **not** indexable.
37
+ - [ ] `apple-touch-icon` (180×180) added - only needed for site which the users might "install".
38
+ - [ ] `site.webmanifest` added - only needed for site which the users might "install".
39
+
40
+ ## Functionality & QA
41
+
42
+ - [ ] All routes load, including on direct visit or refresh (host has SPA fallback routing).
43
+ - [ ] A custom 404 page exists, and React error boundaries catch runtime errors.
44
+ - [ ] No errors or warnings in the browser console.
45
+ - [ ] All forms, links and external integrations work in production.
46
+ - [ ] Design QA is complete and signed off.
47
+ - [ ] The layout works on all viewport widths from 360px up. At minimum, check 360, 768, 1024 and 1440px.
48
+ - [ ] Tested in the latest Chrome, Firefox, Edge and Safari.
49
+
50
+ ## Performance
51
+
52
+ - [ ] Initial JS on first page load is ≤ 175 KB gzipped.
53
+ - [ ] Main CSS file is ≤ 50 KB gzipped.
54
+ - [ ] Images are optimised (WebP/AVIF, correctly sized, ≤ 75 KB each, lazy-loaded below the fold).
55
+ - [ ] Fonts are subset and preloaded, with `font-display: swap`.
56
+ - [ ] Lighthouse scores (run in incognito against production):
57
+
58
+ | Category | Desktop | Mobile |
59
+ |----------------|---------|--------|
60
+ | Performance | ≥ 90 | ≥ 70 |
61
+ | Accessibility | ≥ 90 | ≥ 90 |
62
+ | Best Practices | ≥ 90 | ≥ 90 |
63
+ | SEO | ≥ 90 | ≥ 90 |
64
+
65
+ ## Security & infrastructure
66
+
67
+ - [ ] `npm audit` shows no high or critical vulnerabilities.
68
+ - [ ] `npm audit --omit=dev` shows no vulnerabilities.
69
+ - [ ] No secrets or private API keys in the client bundle.
70
+
71
+ ## Analytics & privacy
72
+
73
+ - [ ] Google Analytics and/or Microsoft Clarity are installed and events are confirmed arriving from production.
@@ -66,22 +66,69 @@ This project uses [Tailwind CSS](https://tailwindcss.com/) for styling and and i
66
66
 
67
67
  To embed the visualization on an external page, include:
68
68
 
69
- **HTML Placeholder**
69
+ ### Option 1: Iframe
70
+
71
+ __HTML Placeholder__
70
72
 
71
73
  ```html
72
- <div id="root"></div>
74
+ <iframe
75
+ id="my-embed"
76
+ src="<url of the app>"
77
+ style="width: 100%; border: 0; display: block;"
78
+ scrolling="no"
79
+ />
73
80
  ```
74
81
 
75
- **Required `<script>` and `<link>` tags**
82
+ __Required `<script>`__
83
+
84
+ ```js
85
+ <script>
86
+ var iframe = document.getElementById('my-embed');
87
+ window.addEventListener('message', function (e) {
88
+ if (e.origin !== 'APP_URL') return;
89
+ if (e.source !== iframe.contentWindow) return;
90
+ if (e.data && e.data.type === 'iframe-height') {
91
+ iframe.style.height = e.data.height + 'px';
92
+ }
93
+ });
94
+ </script>
95
+ ```
96
+
97
+ _This script listens for height messages from the embedded web app and resizes the iframe to match its content, so the app displays without an inner scrollbar._
98
+
99
+ ### Option 2: Embed in the page (Worst performance better UX)
76
100
 
101
+ __HTML Placeholder__
102
+
103
+ ```html
104
+ <div id="root"></div>
77
105
  ```
106
+
107
+ __Required `<script>` and `<link>` tags__
108
+
109
+ ```html
78
110
  <link rel="dns-prefetch" href="{{Visualization URL}}">
79
111
  <script defer="defer" type="module" src="{{Visualization URL}}/index.js"></script>
80
- <link rel="modulepreload" crossorigin href="{{Visualization URL}}/react-{{hash}}.js">
81
- <link rel="modulepreload" crossorigin href="{{Visualization URL}}/undp-{{hash}}.js">
82
112
  <link rel="stylesheet" href="{{Visualization URL}}/style.css"></link>
83
113
  ```
84
114
 
115
+ ## ✅ Launch Checklist
116
+
117
+ Before deploying to production, complete the launch checklist. It covers metadata and SEO, analytics, QA, accessibility, performance, security headers and caching.
118
+
119
+ The checklist is set up as a GitHub issue template, so each launch gets its own tickable copy:
120
+
121
+ 1. Go to **Issues → New issue** in this repository.
122
+ 2. Select **Launch checklist**.
123
+ 3. Assign yourself, and click **Create**.
124
+ 4. Tick items off as you complete them. The issue list shows progress (e.g. "7 of 32 tasks").
125
+
126
+ Or open it directly: [Create launch checklist issue](../../issues/new?template=launch-checklist.md)
127
+
128
+ Don't close the issue until every item is checked, or marked N/A with a reason.
129
+
130
+ The template lives in `.github/ISSUE_TEMPLATE/launch-checklist.md`.
131
+
85
132
  ## 📬 Contact us
86
133
 
87
134
  For questions or feedback, contact us at [data@undp.org](mailto:data@undp.org).
@@ -0,0 +1,73 @@
1
+ ---
2
+ name: Launch checklist
3
+ about: Pre-launch checks to complete before going to production
4
+ title: "Launch checklist"
5
+ labels: launch
6
+ assignees: ''
7
+ ---
8
+
9
+ <!-- Tick items as you go. Don't close this issue until every box is checked or explicitly marked N/A with a reason. -->
10
+
11
+ ## Metadata & SEO
12
+
13
+ - [ ] Favicon added (`favicon.ico` + SVG).
14
+ - [ ] `<meta name="theme-color">` added.
15
+ - [ ] `<html lang="…">` is set correctly.
16
+ - [ ] Every route has a unique `<title>` and `<meta name="description">`.
17
+ - [ ] Every route has a canonical URL: `<link rel="canonical" href="…">`.
18
+ - [ ] Open Graph and Twitter tags are added (globally in `index.html` or per route). Use absolute URLs for `og:url` and `og:image`:
19
+
20
+ ```html
21
+ <meta property="og:type" content="website" />
22
+ <meta property="og:site_name" content="SITE_NAME" />
23
+ <meta property="og:title" content="TITLE" />
24
+ <meta property="og:description" content="DESCRIPTION" />
25
+ <meta property="og:url" content="https://example.com/page" />
26
+ <meta property="og:image" content="https://example.com/og-image.png" />
27
+ <meta property="og:image:width" content="1200" />
28
+ <meta property="og:image:height" content="630" />
29
+ <meta property="og:image:alt" content="IMAGE_ALT_TEXT" />
30
+ <meta name="twitter:card" content="summary_large_image" />
31
+ ```
32
+
33
+ - [ ] Social previews verified with a preview tool (e.g. opengraph.xyz, LinkedIn Post Inspector).
34
+ - [ ] `robots.txt` and `sitemap.xml` are in place.
35
+ - [ ] `<meta name="robots" content="noindex">` is added to routes that should not be indexed for search.
36
+ - [ ] Production is indexable (no leftover `noindex`), and staging is **not** indexable.
37
+ - [ ] `apple-touch-icon` (180×180) added - only needed for site which the users might "install".
38
+ - [ ] `site.webmanifest` added - only needed for site which the users might "install".
39
+
40
+ ## Functionality & QA
41
+
42
+ - [ ] All routes load, including on direct visit or refresh (host has SPA fallback routing).
43
+ - [ ] A custom 404 page exists, and React error boundaries catch runtime errors.
44
+ - [ ] No errors or warnings in the browser console.
45
+ - [ ] All forms, links and external integrations work in production.
46
+ - [ ] Design QA is complete and signed off.
47
+ - [ ] The layout works on all viewport widths from 360px up. At minimum, check 360, 768, 1024 and 1440px.
48
+ - [ ] Tested in the latest Chrome, Firefox, Edge and Safari.
49
+
50
+ ## Performance
51
+
52
+ - [ ] Initial JS on first page load is ≤ 175 KB gzipped.
53
+ - [ ] Main CSS file is ≤ 50 KB gzipped.
54
+ - [ ] Images are optimised (WebP/AVIF, correctly sized, ≤ 75 KB each, lazy-loaded below the fold).
55
+ - [ ] Fonts are subset and preloaded, with `font-display: swap`.
56
+ - [ ] Lighthouse scores (run in incognito against production):
57
+
58
+ | Category | Desktop | Mobile |
59
+ |----------------|---------|--------|
60
+ | Performance | ≥ 90 | ≥ 70 |
61
+ | Accessibility | ≥ 90 | ≥ 90 |
62
+ | Best Practices | ≥ 90 | ≥ 90 |
63
+ | SEO | ≥ 90 | ≥ 90 |
64
+
65
+ ## Security & infrastructure
66
+
67
+ - [ ] `npm audit` shows no high or critical vulnerabilities.
68
+ - [ ] `npm audit --omit=dev` shows no vulnerabilities.
69
+ - [ ] No secrets or private API keys in the client bundle.
70
+
71
+ ## Analytics & privacy
72
+
73
+ - [ ] Google Analytics and/or Microsoft Clarity are installed and events are confirmed arriving from production.
@@ -1,6 +1,7 @@
1
1
  This is a React + TypeScript + Vite project powered by Tailwind CSS, and the UNDP Design System, bootstrapped with [@undp/create-app](https://www.npmjs.com/package/@undp/create-app).
2
2
 
3
3
  It includes:
4
+
4
5
  * React 19.x with React compiler
5
6
  * UNDP Design System
6
7
  * Data fetching with [TanStack Query](https://tanstack.com/query)
@@ -71,22 +72,69 @@ Data fetching is powered by [TanStack Query](https://tanstack.com/query) for eff
71
72
 
72
73
  To embed the visualization on an external page, include:
73
74
 
74
- **HTML Placeholder**
75
+ ### Option 1: Iframe
76
+
77
+ __HTML Placeholder__
75
78
 
76
79
  ```html
77
- <div id="root"></div>
80
+ <iframe
81
+ id="my-embed"
82
+ src="<url of the app>"
83
+ style="width: 100%; border: 0; display: block;"
84
+ scrolling="no"
85
+ />
86
+ ```
87
+
88
+ __Required `<script>`__
89
+
90
+ ```js
91
+ <script>
92
+ var iframe = document.getElementById('my-embed');
93
+ window.addEventListener('message', function (e) {
94
+ if (e.origin !== 'APP_URL') return;
95
+ if (e.source !== iframe.contentWindow) return;
96
+ if (e.data && e.data.type === 'iframe-height') {
97
+ iframe.style.height = e.data.height + 'px';
98
+ }
99
+ });
100
+ </script>
78
101
  ```
79
102
 
80
- **Required `<script>` and `<link>` tags**
103
+ _This script listens for height messages from the embedded web app and resizes the iframe to match its content, so the app displays without an inner scrollbar._
81
104
 
105
+ ### Option 2: Embed in the page (Worst performance better UX)
106
+
107
+ __HTML Placeholder__
108
+
109
+ ```html
110
+ <div id="root"></div>
82
111
  ```
112
+
113
+ __Required `<script>` and `<link>` tags__
114
+
115
+ ```html
83
116
  <link rel="dns-prefetch" href="{{Visualization URL}}">
84
117
  <script defer="defer" type="module" src="{{Visualization URL}}/index.js"></script>
85
- <link rel="modulepreload" crossorigin href="{{Visualization URL}}/react-{{hash}}.js">
86
- <link rel="modulepreload" crossorigin href="{{Visualization URL}}/undp-{{hash}}.js">
87
118
  <link rel="stylesheet" href="{{Visualization URL}}/style.css"></link>
88
119
  ```
89
120
 
121
+ ## ✅ Launch Checklist
122
+
123
+ Before deploying to production, complete the launch checklist. It covers metadata and SEO, analytics, QA, accessibility, performance, security headers and caching.
124
+
125
+ The checklist is set up as a GitHub issue template, so each launch gets its own tickable copy:
126
+
127
+ 1. Go to **Issues → New issue** in this repository.
128
+ 2. Select **Launch checklist**.
129
+ 3. Assign yourself, and click **Create**.
130
+ 4. Tick items off as you complete them. The issue list shows progress (e.g. "7 of 32 tasks").
131
+
132
+ Or open it directly: [Create launch checklist issue](../../issues/new?template=launch-checklist.md)
133
+
134
+ Don't close the issue until every item is checked, or marked N/A with a reason.
135
+
136
+ The template lives in `.github/ISSUE_TEMPLATE/launch-checklist.md`.
137
+
90
138
  ## 📬 Contact us
91
139
 
92
140
  For questions or feedback, contact us at [data@undp.org](mailto:data@undp.org).