Obiz Solutions — this very site
This is the site you’re reading right now. The goal: a place to share systems, solutions, and things I’ve learned, available in English (default) and Vietnamese, fast to load, and close to zero to run.
Architecture
The path from writing a post to a reader seeing it:
- Content — posts are Markdown files under
src/content/{blog,projects,docs}, each with a matchingen/andvi/translation. - A
git pushtomaintriggers the GitHub Actions workflow. - GitHub Actions installs dependencies, runs
astro checkthenastro build— Astro reads the Content Collections and renders every page to static HTML underdist/. - Actions authenticates to AWS via OIDC (no long-lived access keys
stored anywhere), then runs
aws s3 sync dist/ s3://bucket --deleteto sync the latest build and remove stale files. - CloudFront sits in front of the S3 bucket, serving content over a
CDN with HTTPS; Actions calls
create-invalidationto clear the cache right after each deploy. - The visitor’s browser gets back static HTML with next to no JavaScript, thanks to Astro’s Islands Architecture — see What is Astro? for more.
Content model
The three collections — blog, projects, docs — share one convention:
each entry is a Markdown file under an en/ or vi/ folder, with
frontmatter validated by a Zod schema in src/content/config.ts (see
What is TypeScript? for why that matters). A wrong
type or a missing field fails at astro build time, before it can ever
reach production.
Bilingual routing
Astro’s i18n routing makes English the default (root route /), with
Vietnamese under a /vi/ prefix. The LanguageSwitcher component computes
the equivalent path in the other language from the current URL, and the
Header figures out which nav item is active from Astro.url.pathname.
Contact form
The site has no backend, so the contact form on /contact POSTs straight
to Web3Forms, a form-relay service that emails
each submission through. The access key is injected at build time from a
PUBLIC_WEB3FORMS_ACCESS_KEY variable — the GitHub Actions workflow passes
it into astro build. If the key is missing, the form isn’t rendered at
all and the page falls back to plain contact details (email, LinkedIn,
phone). A small progressive-enhancement script submits via fetch and
shows an inline status message; with JavaScript disabled the form still
works as an ordinary POST. It’s the only client-side JavaScript on the
site.
Why this stack
- Astro: the site is mostly content — no need for a heavy SPA runtime.
- S3 + CloudFront: cheap static hosting, no server to manage, scales on its own.
- GitHub Actions + OIDC: every push deploys automatically, without storing AWS access keys anywhere — less credential-leak surface.