@@ -124,6 +124,43 @@ Brand components with no Bootstrap equivalent (`Logo`, `Avatar`) are tiny hand-w
124124components in ` src/components/ ` , not a vendored bundle. Everything else — buttons, badges,
125125forms, the Codi/Enroll drawers — is react-bootstrap, restyled via the SCSS above.
126126
127+ ## Deployment
128+
129+ ` .github/workflows/deploy.yml ` builds the site and rsyncs ` dist/ ` to the
130+ "CodeBoxx Web Claude" DigitalOcean Droplet over SSH on every push to ` main ` (or
131+ manually via "Run workflow"). It does not provision anything — the Droplet, nginx,
132+ the ` deploy ` user, and the target directory are already set up (see below).
133+
134+ Required repo secrets (Settings → Secrets and variables → Actions):
135+
136+ | Secret | Value |
137+ | ------------------------- | --------------------------------------------------------------------- |
138+ | ` VITE_SANITY_PROJECT_ID ` | Same as ` .env ` 's ` VITE_SANITY_PROJECT_ID ` |
139+ | ` VITE_SANITY_DATASET ` | Same as ` .env ` 's ` VITE_SANITY_DATASET ` |
140+ | ` VITE_SANITY_API_VERSION ` | Same as ` .env ` 's ` VITE_SANITY_API_VERSION ` |
141+ | ` VITE_SANITY_TOKEN ` | Same as ` .env ` 's ` VITE_SANITY_TOKEN ` (blank is fine if unset there) |
142+ | ` DROPLET_HOST ` | ` 159.223.145.47 ` |
143+ | ` DROPLET_USER ` | ` deploy ` — a dedicated, non-root, key-only user with no sudo |
144+ | ` DROPLET_SSH_KEY ` | Private half of the ` deploy ` user's dedicated deploy key (no passphrase) |
145+ | ` DROPLET_TARGET_PATH ` | ` /var/www/codeboxx ` |
146+
147+ On the Droplet (already done for "CodeBoxx Web Claude"):
148+
149+ - nginx installed and enabled, serving ` /var/www/codeboxx ` with
150+ ` try_files $uri /index.html; ` in its ` location / ` block — required because this
151+ is a client-side-routed SPA (` react-router ` ` BrowserRouter ` ); without the
152+ fallback, deep links like ` /blog/some-post ` 404 on a hard refresh.
153+ - A ` deploy ` system user owns ` /var/www/codeboxx ` , has no sudo access, and accepts
154+ SSH only via the dedicated deploy key (password auth disabled). Its
155+ ` authorized_keys ` holds only that key's public half.
156+ - No domain/TLS yet — nginx answers on port 80 for any ` Host ` (catch-all
157+ ` server_name _; ` ). Point a domain's A record at the Droplet and run `certbot
158+ --nginx` later to add HTTPS; update ` server_name` accordingly at that point.
159+
160+ The deploy step runs ` rsync --delete ` , so ` DROPLET_TARGET_PATH ` should stay
161+ dedicated to this site — anything else living in that directory gets removed to
162+ match ` dist/ ` .
163+
127164## Structure
128165
129166```
0 commit comments