Skip to content

Denuo-Web/DenuoWebSite

Repository files navigation

Denuo Web, LLC site

A Firebase + Google Cloud Run powered site for Denuo Web, LLC. The frontend is a Vite/React app with a Firebase-authenticated admin dashboard that edits Firestore-driven content. The backend is a minimal Express API deployed to Cloud Run for contact capture and admin utilities. CI/CD is wired through GitHub Actions.

Current public positioning: Denuo Web is Jaron Rosenau's software delivery practice for practical API-driven web apps, integrations, marketplace workflows, internal tools, operational tooling, and supportable launches. Public case studies are organized around three offers: Discovery / Implementation Plan, Web App / Integration Build, and Stabilize / Support Handoff.

Prerequisites

  • Node.js 20 (use nvm use 20 or install via nvm) + npm
  • Firebase CLI: npm install -g firebase-tools
  • Terraform >= 1.6 (if using infra/terraform)
  • Google Cloud SDK (gcloud) if you plan to deploy/run Cloud Run manually or authenticate Terraform via ADC
  • GitHub access to set repo secrets for CI/CD

Project layout

  • web/ – React + Vite SPA with Firebase Auth + Firestore-driven content and admin dashboard
  • api/ – Express API for Cloud Run (/health, /contact, /admin/status)
  • firebase.json / .firebaserc – Hosting + Cloud Run rewrite config
  • firestore.rules – Secures site content + contact submissions
  • .github/workflows/ – Deploy pipelines for Hosting and Cloud Run
  • docs/SPEC.md – Specification and feature outline for the site
  • .env.example – Sample values for CI/CD secrets (set in GitHub, not committed)
  • web/src/i18n/ – Localization strings (EN/JA) used by the UI toggles
  • infra/terraform/ – Scaffold to enable APIs, create deploy service account, Artifact Registry, and push GitHub secrets

Frontend (Firebase Hosting)

  1. Copy web/.env.example to web/.env and fill your Firebase web app values.
  2. Install deps and run locally:
    cd web
    npm install
    npm run dev
  3. Build for release: npm run build (outputs to web/dist).

The admin dashboard writes to Firestore siteContent/public (plus work sub-documents under siteContent/public/work/{slug} for case studies). Contact submissions are backend-only (/api/contact) and should not be client-written to Firestore.

Firebase Emulator Suite (local)

  • Toggle VITE_USE_FIREBASE_EMULATORS=true in web/.env to point the SPA to local emulators.
  • Start emulators (requires firebase-tools):
    firebase emulators:start --only auth,firestore --project $FIREBASE_PROJECT_ID
  • Auth emulator runs on :9099 and Firestore emulator on :8080 (matching firebase.json). Hosting emulator is configured on :5000 if you prefer serving the built app via firebase emulators:start --only hosting,auth,firestore.
  • Radix UI Themes handles the light/dark toggle; appearance choice persists locally.
  • Language toggle (EN/JA) is driven by src/i18n/uiCopy.ts; UI labels fall back to English when translations are missing.

Backend (Cloud Run API)

  1. Install deps: cd api && npm install.
  2. Local run (requires application default or FIREBASE_SERVICE_ACCOUNT env): npm run dev.
  3. Optional Stripe invoicing: set STRIPE_SECRET_KEY to enable /billing/invoice (admin-only).
  4. Deploy to Cloud Run (example):
    gcloud builds submit api --tag gcr.io/$PROJECT_ID/denuo-api
    gcloud run deploy denuo-api \
      --image gcr.io/$PROJECT_ID/denuo-api \
      --region us-central1 \
      --allow-unauthenticated

Endpoints:

  • GET /health – service health
  • POST /contact{ name, email, project?, message, captchaToken?, website? }; stores normalized payload in Firestore contactRequests when credentials are present
  • GET /admin/status – requires Firebase ID token with admin: true custom claim
  • POST /billing/invoice – admin-only; creates and emails a Stripe invoice ({ email, name, amountCents, description? })

Contact endpoint protections:

  • In-memory IP-based rate limiting (CONTACT_RATE_LIMIT_WINDOW_MS, CONTACT_RATE_LIMIT_MAX_REQUESTS)
  • Optional Firebase App Check verification (CONTACT_REQUIRE_APP_CHECK=true, send x-firebase-appcheck header)
  • Optional Turnstile CAPTCHA verification (CONTACT_REQUIRE_CAPTCHA=true, TURNSTILE_SECRET_KEY, send captchaToken)
  • Optional origin allowlist (CONTACT_ALLOWED_ORIGINS)
  • Payload normalization + length limits + honeypot field (website)

Firestore rules

Deploy rules to lock down writes to admin-only users, allow public reads for marketing content, and deny client-side writes to contactRequests:

firebase deploy --only firestore:rules

Set an admin claim

Use a service account with Firebase Auth admin permissions:

export FIREBASE_SERVICE_ACCOUNT="$(cat path/to/serviceAccount.json)"
node api/scripts/setAdminClaim.js --email=you@example.com

GitHub Actions / secrets

Set these repo secrets before enabling CI/CD (Terraform will populate them by default using the generated deployer key for both Hosting and Cloud Run):

  • FIREBASE_SERVICE_ACCOUNT – JSON for a Firebase Hosting deploy service account
  • FIREBASE_PROJECT_ID – Firebase project id
  • GCP_SERVICE_ACCOUNT_KEY – JSON key with Cloud Run + Artifact Registry permissions
  • GCP_PROJECT_ID – Google Cloud project id
  • GCP_REGION – Cloud Run region (e.g., us-central1)
  • STRIPE_SECRET_KEY – Stripe secret (for invoicing API)
  • TURNSTILE_SECRET_KEY – Turnstile secret for contact CAPTCHA verification
  • CONTACT_IP_HASH_SALT – random salt used to hash IP metadata before persistence
  • A sample .env.example at repo root lists these keys (for local reference only; do not commit secrets).
  • Optionally, set (or let Terraform set) GitHub Actions variables for the Vite web config so production builds enable auth/App Check: VITE_FIREBASE_API_KEY, VITE_FIREBASE_AUTH_DOMAIN, VITE_FIREBASE_PROJECT_ID, VITE_FIREBASE_STORAGE_BUCKET, VITE_FIREBASE_MESSAGING_SENDER_ID, VITE_FIREBASE_APP_ID, VITE_FIREBASE_APP_CHECK_SITE_KEY, and VITE_USE_FIREBASE_EMULATORS (usually false).

deploy-hosting.yml builds web and deploys Hosting. deploy-cloudrun.yml builds and deploys api to Cloud Run when api/** changes.

Content model

  • Live content stored at Firestore siteContent/public; case studies are stored as documents at siteContent/public/work/{slug}. Fallback content in web/src/content/fallback.ts is built from Jaron Rosenau's current positioning and recent work (Moonshine Art, QuestByCycle, CrowdPM Platform, APK Workbench, DripCopy).
  • Services, projects, differentiators, process, contact info, and work metadata (servicePackages, testimonials) are editable via /admin after signing in.
  • Admin can send Stripe invoices from /admin when the API has STRIPE_SECRET_KEY set; the UI uses the authenticated Firebase ID token.

Localization best practices

  • Keep UI strings in web/src/i18n/uiCopy.ts; avoid hard-coding labels inside components.
  • For translated site content, mirror the schema per locale (e.g., siteContent/public/translations/ja) and keep keys consistent.
  • Default to English when translations are absent; prefer full-sentence keys to preserve Japanese line breaks.
  • Ship locale files through CI (export/import JSON) to keep translators and releases in sync.
  • /admin now includes Localization JSON (EN/JA) tools to export a language pack, import updated JSON, and save it to siteContent/public/translations/{en|ja}.

Firebase Hosting rewrite

Requests to /api/** are proxied to the Cloud Run service denuo-api in us-central1 via the firebase.json rewrite. Update serviceId/region if you change the Cloud Run deployment.

Quick start (minimal local preview)

  1. npm install in both web/ and api/.
  2. For a zero-config preview, skip env files and run npm run dev in web/; the site will use bundled fallback content and disable saves/admin actions (auth/API not configured).
  3. To enable live Firestore/auth, fill web/.env with Firebase web config.
  4. (Optional) Set VITE_USE_FIREBASE_EMULATORS=true and run firebase emulators:start --only auth,firestore for local auth/content editing.
  5. Run npm run dev in web/ for the SPA; run npm run dev in api/ for the API.
  6. Visit /admin to sign in and edit content (admin claim required to save to Firestore).

Terraform scaffold

  • See infra/terraform/README.md for automating API enablement, deploy service account, Artifact Registry, and pushing GitHub Actions secrets (including Stripe). Squarespace DNS is not managed; migrate DNS to a Terraform-capable provider if you want full automation for records.

Portfolio Case Study

This repository is part of Jaron Rosenau's implementation, developer-support, and integration engineering portfolio. The public case study summarizes the problem, delivery scope, architecture, and operational result.

About

Denuo Web public site with Firebase Hosting, Firestore content admin, and Cloud Run API.

Topics

Resources

Stars

Watchers

Forks

Contributors