Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion api/config/initializers/app_origin.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
configured_origin = ENV["FRONTEND_URL"].presence || ENV["APP_URL"].presence
default_origin = Rails.env.production? ? "https://hafa-code.netlify.app" : "http://localhost:5173"
default_origin = Rails.env.production? ? "https://code.shimizu-technology.com" : "http://localhost:5173"

Rails.application.config.x.public_app_origin = (configured_origin || default_origin).delete_suffix("/")
2 changes: 1 addition & 1 deletion api/test/integration/projects_api_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1075,7 +1075,7 @@ class ProjectsApiTest < ActionDispatch::IntegrationTest
Rails.define_singleton_method(:env) { ActiveSupport::StringInquirer.new("production") }
load Rails.root.join("config/initializers/app_origin.rb")

assert_equal "https://hafa-code.netlify.app", Api::V1::OrganizationsController.new.send(:frontend_origin)
assert_equal "https://code.shimizu-technology.com", Api::V1::OrganizationsController.new.send(:frontend_origin)
ensure
Rails.define_singleton_method(:env, old_rails_env) if old_rails_env
Rails.application.config.x.public_app_origin = old_public_app_origin
Expand Down
36 changes: 36 additions & 0 deletions docs/DOMAIN_CUTOVER.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Håfa Code domain cutover

Håfa Code's canonical public address is `https://code.shimizu-technology.com`.
The original `https://hafa-code.netlify.app` address remains available as a
recovery path for browser-local work. The private code-server installation that
previously used `code.shimizu-technology.com` now uses
`https://ide.shimizu-technology.com`.

## Why the old Netlify address stays online

Browser storage belongs to an origin. Projects, checkpoints, Practice Lab
progress, and preferences saved at `hafa-code.netlify.app` do not automatically
appear at `code.shimizu-technology.com`. The app therefore provides a complete,
versioned workspace backup:

1. Open the old Netlify address and choose **Workspace backup**.
2. Download the complete backup.
3. Open `code.shimizu-technology.com`, choose **Workspace backup**, and restore
the file.

Restore merges matching records and preserves work already present in the new
origin. Cloud projects still load from the signed-in account.

## Production configuration

- Netlify serves the web app and owns the custom domain.
- Cloudflare DNS points `code` to the Netlify site and routes `ide` through the
private code-server tunnel.
- Render uses `FRONTEND_URL=https://code.shimizu-technology.com` so generated
links use the canonical host.
- Render's `ALLOWED_ORIGINS` includes both the canonical host and the Netlify
recovery host during the migration period.
- Clerk must allow the canonical host before signed-in production QA.

After any domain change, verify the canonical metadata, TLS, sign-in, API CORS,
project sync, every in-browser language runner, and desktop/mobile layouts.
20 changes: 10 additions & 10 deletions docs/FDMS_CLASSROOM_LAUNCH_PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
**Version:** 1.1
**Audit date:** July 25, 2026
**Target:** Father Dueñas Memorial School classroom use during the 2026–2027 school year
**Production frontend:** <https://hafa-code.netlify.app/>
**Production frontend:** <https://code.shimizu-technology.com/>
**Production API:** <https://hafa-code.onrender.com/>
**Current recommendation:** **Repository-ready after this hardening PR; production launch remains conditional on the deployment, school, backup, monitoring, and pilot gates below**

Expand Down Expand Up @@ -67,19 +67,19 @@ These checks were performed against the production URLs on July 25, 2026, before
| Netlify-origin API preflight | Missing `Access-Control-Allow-Origin` | Baseline production cannot use the API from the current origin. The branch fixes the application default; redeployment and a production preflight remain required. |
| Localhost API preflight | Allowed | Current Render CORS configuration appears to allow localhost instead of production. |
| Production page rendering | Successful | The signed-out editor, runner controls, project library, visibility UI, and responsive structure load. |
| Canonical and social metadata | Points to `https://hafacode.com/` | Baseline metadata is stale. The branch aligns canonical, social, robots, and sitemap URLs to Netlify. |
| Canonical and social metadata | Points to `https://hafacode.com/` | Baseline metadata is stale. The branch aligns canonical, social, robots, and sitemap URLs to `code.shimizu-technology.com`. |
| API authentication/class workflows | Not production-verifiable while CORS is blocked | Must be tested after the origin configuration is corrected. |

### Correction to the earlier domain finding

The earlier concern should be stated precisely:

- The application is available at `https://hafa-code.netlify.app/`.
- The application is available at `https://code.shimizu-technology.com/`.
- The Netlify frontend is not down.
- The production Rails API is healthy.
- The baseline break is that the API does not authorize `https://hafa-code.netlify.app` as a CORS origin.
- The baseline break was that the API did not authorize the production frontend as a CORS origin.
- `hafacode.com` is a stale or future canonical domain in the baseline metadata, not the URL students should use today.
- The hardening branch declares the Netlify URL as the production application origin and always includes it in CORS, while preserving an environment override for a future domain.
- The hardening branch declares `https://code.shimizu-technology.com` as the production application origin. The original Netlify host remains an explicit recovery origin for browser-local workspace transfer.

That makes the finding more actionable: align Render, Netlify, Clerk, invitation links, and metadata around one declared production origin.

Expand Down Expand Up @@ -171,13 +171,13 @@ For the initial FDMS launch, default every class project to **Teacher only**, of

**Work:**

- [ ] Set Render `ALLOWED_ORIGINS` to include `https://hafa-code.netlify.app`.
- [ ] Set Render `FRONTEND_URL` or `APP_URL` to `https://hafa-code.netlify.app` so invitation links use the live site.
- [ ] Set Render `ALLOWED_ORIGINS` to include `https://code.shimizu-technology.com` and the `https://hafa-code.netlify.app` recovery origin.
- [ ] Set Render `FRONTEND_URL` or `APP_URL` to `https://code.shimizu-technology.com` so invitation links use the canonical site.
- [ ] Verify Netlify `VITE_API_URL` points to `https://hafa-code.onrender.com`.
- [ ] Verify Clerk production allowed origins and redirect URLs include the Netlify domain.
- [ ] Decide whether `hafacode.com` will be launched now or later.
- [ ] Verify Clerk production allowed origins and redirect URLs include `https://code.shimizu-technology.com`; retain the Netlify host only where the recovery flow requires it.
- [x] Use `code.shimizu-technology.com` as the canonical host; do not depend on `hafacode.com` for this launch.
- [x] Change canonical, Open Graph, Twitter, JSON-LD, robots, sitemap, and share image URLs to the declared production domain.
- [ ] If both a custom domain and Netlify domain remain valid, configure redirects and allow both origins deliberately.
- [ ] Keep the Netlify recovery host available without redirecting it so users can export origin-bound browser data; allow both frontend origins deliberately in Render CORS.

**Acceptance criteria:**

Expand Down
14 changes: 7 additions & 7 deletions web/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,26 +18,26 @@
<meta name="msapplication-TileColor" content="#14110f" />

<meta property="og:type" content="website" />
<meta property="og:url" content="https://hafa-code.netlify.app/" />
<meta property="og:url" content="https://code.shimizu-technology.com/" />
<meta property="og:site_name" content="Hafa Code" />
<meta property="og:title" content="Hafa Code | Browser Coding Playground" />
<meta property="og:description" content="Run Ruby, JavaScript, Python, Java, HTML, and CSS in a beginner-friendly browser playground for Guam students." />
<meta property="og:image" content="https://hafa-code.netlify.app/og.png" />
<meta property="og:image" content="https://code.shimizu-technology.com/og.png" />
<meta property="og:image:type" content="image/png" />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="twitter:card" content="summary_large_image" />
<meta property="twitter:url" content="https://hafa-code.netlify.app/" />
<meta property="twitter:url" content="https://code.shimizu-technology.com/" />
<meta property="twitter:title" content="Hafa Code | Browser Coding Playground" />
<meta property="twitter:description" content="A tiny Replit alternative for CSG and FD students." />
<meta property="twitter:image" content="https://hafa-code.netlify.app/og.png" />
<meta property="twitter:image" content="https://code.shimizu-technology.com/og.png" />

<link rel="icon" type="image/png" sizes="64x64" href="/favicon.png" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<link rel="icon" type="image/png" sizes="192x192" href="/icons/icon-192.png" />
<link rel="icon" type="image/png" sizes="512x512" href="/icons/icon-512.png" />
<link rel="manifest" href="/manifest.json" />
<link rel="canonical" href="https://hafa-code.netlify.app/" />
<link rel="canonical" href="https://code.shimizu-technology.com/" />

<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
Expand All @@ -49,15 +49,15 @@
"@type": "WebApplication",
"name": "Hafa Code",
"alternateName": "Hafa Code Playground",
"url": "https://hafa-code.netlify.app/",
"url": "https://code.shimizu-technology.com/",
"description": "A beginner-friendly browser coding playground for Ruby, JavaScript, Python, Java, HTML, and CSS.",
"applicationCategory": "EducationalApplication",
"operatingSystem": "Any",
"browserRequirements": "Requires a modern browser with WebAssembly and Web Worker support.",
"creator": {
"@type": "Organization",
"name": "Shimizu Technology",
"url": "https://shimizutechnology.com/"
"url": "https://shimizu-technology.com/"
},
"offers": {
"@type": "Offer",
Expand Down
Binary file modified web/public/og.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions web/public/og.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions web/public/robots.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Hafa Code
# https://hafa-code.netlify.app
# https://code.shimizu-technology.com

User-agent: *
Allow: /
Disallow: /api/
Disallow: /admin/
Disallow: /rails/

Sitemap: https://hafa-code.netlify.app/sitemap.xml
Sitemap: https://code.shimizu-technology.com/sitemap.xml
4 changes: 2 additions & 2 deletions web/public/sitemap.xml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://hafa-code.netlify.app/</loc>
<lastmod>2026-04-30</lastmod>
<loc>https://code.shimizu-technology.com/</loc>
<lastmod>2026-09-04</lastmod>
<changefreq>weekly</changefreq>
<priority>1.0</priority>
</url>
Expand Down
94 changes: 94 additions & 0 deletions web/src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,42 @@ h2 {
flex: 0 0 auto;
}

.domain-move-banner {
align-items: center;
background: #14110f;
border: 1px solid rgba(248, 184, 78, 0.5);
border-radius: 1.2rem;
color: #fffaf1;
display: flex;
gap: 1rem;
justify-content: space-between;
margin-bottom: 1rem;
padding: 0.9rem 1rem;
}

.domain-move-banner > div:first-child {
display: grid;
gap: 0.25rem;
}

.domain-move-banner span {
color: #d8cbbb;
line-height: 1.4;
}

.domain-move-actions {
align-items: center;
display: flex;
flex: 0 0 auto;
gap: 0.75rem;
}

.domain-move-actions a {
color: #fffaf1;
font-weight: 800;
white-space: nowrap;
}

.context-bar {
align-items: center;
display: grid;
Expand Down Expand Up @@ -3015,6 +3051,43 @@ button.context-chip.active,
width: 100%;
}

.workspace-transfer-sheet {
width: min(590px, 100%);
}

.domain-move-instructions,
.transfer-callout {
background: rgba(248, 184, 78, 0.16);
border: 1px solid rgba(248, 184, 78, 0.5);
border-radius: 1rem;
color: var(--ink);
line-height: 1.5;
margin: 1rem 0 0;
padding: 0.85rem 1rem;
}

.domain-move-instructions ol {
margin: 0.55rem 0 0;
padding-left: 1.2rem;
}

.domain-move-instructions a {
color: var(--lagoon);
font-weight: 800;
}

.workspace-transfer-actions {
display: grid;
gap: 0.7rem;
grid-template-columns: repeat(2, minmax(0, 1fr));
margin-top: 1rem;
}

.workspace-transfer-actions button {
border-radius: 1rem;
min-height: 52px;
}

.confirm-copy {
color: var(--muted);
line-height: 1.5;
Expand Down Expand Up @@ -3153,6 +3226,27 @@ button.context-chip.active,
}

@media (max-width: 640px) {
.domain-move-banner {
align-items: stretch;
flex-direction: column;
font-size: 0.88rem;
}

.domain-move-actions {
align-items: stretch;
display: grid;
grid-template-columns: 1fr;
}

.domain-move-actions a {
padding: 0.45rem;
text-align: center;
}

.workspace-transfer-actions {
grid-template-columns: 1fr;
}

:root { --workspace-pane-height: clamp(380px, 68vh, 560px); }

.app-shell {
Expand Down
Loading