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
5 changes: 5 additions & 0 deletions .firebaserc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"projects": {
"default": "servio-app"
}
}
51 changes: 51 additions & 0 deletions .github/workflows/firebase-deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: Deploy to Firebase Hosting

on:
push:
branches: [main]
workflow_dispatch:

permissions:
contents: read

concurrency:
group: firebase-deploy-${{ github.ref }}
cancel-in-progress: true

jobs:
build-and-deploy:
name: Build & Deploy
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4
Comment on lines +21 to +22

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

find . -name "firebase-deploy.yml" -type f

Repository: hrx01-dev/Servio

Length of output: 100


🏁 Script executed:

cat -n .github/workflows/firebase-deploy.yml

Repository: hrx01-dev/Servio

Length of output: 1947


🌐 Web query:

actions/checkout@v4 persist-credentials default behavior security

💡 Result:

In actions/checkout@v4, the persist-credentials input defaults to true [1][2]. When set to true (the default), the action configures the local Git repository's configuration files within the runner to include the authentication token or SSH key used for the checkout [3][2]. This enables subsequent steps in the same job to execute authenticated Git commands (such as git push or git fetch) without needing to manually re-authenticate [3][4]. The action is designed to remove these credentials during the post-job cleanup phase [3][2]. From a security perspective, there has been long-standing community discussion regarding this default behavior [5][6]. The primary security concern is that by persisting these credentials, any subsequent step in the workflow—including potentially untrusted third-party actions—gains the ability to access and utilize these credentials for the duration of the job [5][6]. To opt out of this behavior and prevent the credentials from being written to the local Git configuration, you should explicitly set the input to false in your workflow definition [3][2]: - uses: actions/checkout@v4 with: persist-credentials: false It is recommended to use the principle of least privilege by configuring appropriate permissions for your GitHub Actions tokens, regardless of this setting [3][6].

Citations:


Pin actions to commit SHAs and disable credential persistence.

Line 22 persists checkout credentials by default (persist-credentials defaults to true), and lines 22, 25, and 46 use mutable action tags. Pin actions to immutable commit SHAs and set persist-credentials: false on the checkout action to reduce supply chain attack surface.

Suggested hardening pattern
       - name: Checkout
-        uses: actions/checkout@v4
+        uses: actions/checkout@<full-commit-sha>
+        with:
+          persist-credentials: false

       - name: Set up Node.js
-        uses: actions/setup-node@v4
+        uses: actions/setup-node@<full-commit-sha>

...
-        uses: FirebaseExtended/action-hosting-deploy@v0
+        uses: FirebaseExtended/action-hosting-deploy@<full-commit-sha>

Also applies to: 24-26, 46-46

🧰 Tools
🪛 zizmor (1.25.2)

[warning] 21-22: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[error] 22-22: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/firebase-deploy.yml around lines 21 - 22, The GitHub
Actions in the firebase-deploy workflow use mutable version tags instead of
immutable commit SHAs, and the checkout action does not disable credential
persistence. For the actions/checkout action at line 22, replace the mutable tag
`v4` with a specific commit SHA and add the `persist-credentials: false`
configuration option to reduce supply chain attack surface. Apply the same
commit SHA pinning pattern to the other actions referenced on lines 24-26 and
line 46 to ensure all actions are pinned to immutable references.

Source: Linters/SAST tools


- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: npm

- name: Install dependencies
run: npm ci

- name: Build
run: npm run build
env:
VITE_FIREBASE_API_KEY: ${{ secrets.VITE_FIREBASE_API_KEY }}
VITE_FIREBASE_AUTH_DOMAIN: ${{ secrets.VITE_FIREBASE_AUTH_DOMAIN }}
VITE_FIREBASE_PROJECT_ID: ${{ secrets.VITE_FIREBASE_PROJECT_ID }}
VITE_FIREBASE_STORAGE_BUCKET: ${{ secrets.VITE_FIREBASE_STORAGE_BUCKET }}
VITE_FIREBASE_MESSAGING_SENDER_ID: ${{ secrets.VITE_FIREBASE_MESSAGING_SENDER_ID }}
VITE_FIREBASE_APP_ID: ${{ secrets.VITE_FIREBASE_APP_ID }}
VITE_FIREBASE_MEASUREMENT_ID: ${{ secrets.VITE_FIREBASE_MEASUREMENT_ID }}

- name: Deploy to Firebase Hosting
if: ${{ secrets.FIREBASE_SERVICE_ACCOUNT != '' }}
uses: FirebaseExtended/action-hosting-deploy@v0
with:
repoToken: ${{ secrets.GITHUB_TOKEN }}
firebaseServiceAccount: ${{ secrets.FIREBASE_SERVICE_ACCOUNT }}
channelId: live
projectId: ${{ secrets.VITE_FIREBASE_PROJECT_ID }}
Comment on lines +44 to +51

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

GitHub Actions secrets in if condition expression allowed syntax

💡 Result:

You cannot directly reference secrets in GitHub Actions if conditional expressions [1][2][3]. Attempting to use syntax like ${{ secrets.MY_SECRET }} within an if block will not function as expected, as the secrets context is not available for evaluation at that stage of the workflow execution [1][3]. To conditionally run a job or step based on the presence or value of a secret, use the following workaround: 1. Map the secret to an environment variable at the job or step level [1][4]. 2. Use that environment variable to evaluate the condition [4][3]. Example of using a secret to conditionally run a step: jobs: example-job: runs-on: ubuntu-latest steps: - name: Set secret as environment variable env: MY_SECRET_VAR: ${{ secrets.MY_SECRET }} run: | echo "SECRET_EXISTS=${{ env.MY_SECRET_VAR!= '' }}" >> $GITHUB_ENV - name: Conditional step if: env.SECRET_EXISTS == 'true' run: echo "The secret is defined." Alternatively, if you only need to check if any secrets are available (for example, to prevent a job from running on an external pull request where secrets are restricted), you can use the github.secret_source context in your if conditional [3]: jobs: my-job: runs-on: ubuntu-latest if: ${{ github.secret_source == 'Actions' }} steps: - run: echo "Secrets are available."

Citations:


🏁 Script executed:

# Check if the repository has the firebase-deploy.yml file and examine the context
git ls-files | grep -i firebase

Repository: hrx01-dev/Servio

Length of output: 323


🏁 Script executed:

cat -n .github/workflows/firebase-deploy.yml | sed -n '40,55p'

Repository: hrx01-dev/Servio

Length of output: 770


Use env for the deploy gate instead of secrets in if expression.

Line 45 uses secrets directly in the if condition, which is not allowed in GitHub Actions. The secrets context is unavailable at the workflow conditional evaluation stage and will cause the workflow to fail validation. Gate on an environment variable instead by mapping the secret to env first.

Suggested fix
       - name: Deploy to Firebase Hosting
-        if: ${{ secrets.FIREBASE_SERVICE_ACCOUNT != '' }}
+        env:
+          FIREBASE_SERVICE_ACCOUNT: ${{ secrets.FIREBASE_SERVICE_ACCOUNT }}
+        if: ${{ env.FIREBASE_SERVICE_ACCOUNT != '' }}
         uses: FirebaseExtended/action-hosting-deploy@v0
         with:
           repoToken: ${{ secrets.GITHUB_TOKEN }}
-          firebaseServiceAccount: ${{ secrets.FIREBASE_SERVICE_ACCOUNT }}
+          firebaseServiceAccount: ${{ env.FIREBASE_SERVICE_ACCOUNT }}
           channelId: live
           projectId: ${{ secrets.VITE_FIREBASE_PROJECT_ID }}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Deploy to Firebase Hosting
if: ${{ secrets.FIREBASE_SERVICE_ACCOUNT != '' }}
uses: FirebaseExtended/action-hosting-deploy@v0
with:
repoToken: ${{ secrets.GITHUB_TOKEN }}
firebaseServiceAccount: ${{ secrets.FIREBASE_SERVICE_ACCOUNT }}
channelId: live
projectId: ${{ secrets.VITE_FIREBASE_PROJECT_ID }}
- name: Deploy to Firebase Hosting
env:
FIREBASE_SERVICE_ACCOUNT: ${{ secrets.FIREBASE_SERVICE_ACCOUNT }}
if: ${{ env.FIREBASE_SERVICE_ACCOUNT != '' }}
uses: FirebaseExtended/action-hosting-deploy@v0
with:
repoToken: ${{ secrets.GITHUB_TOKEN }}
firebaseServiceAccount: ${{ env.FIREBASE_SERVICE_ACCOUNT }}
channelId: live
projectId: ${{ secrets.VITE_FIREBASE_PROJECT_ID }}
🧰 Tools
🪛 actionlint (1.7.12)

[error] 45-45: context "secrets" is not allowed here. available contexts are "env", "github", "inputs", "job", "matrix", "needs", "runner", "steps", "strategy", "vars". see https://docs.github.com/en/actions/learn-github-actions/contexts#context-availability for more details

(expression)

🪛 zizmor (1.25.2)

[error] 46-46: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/firebase-deploy.yml around lines 44 - 51, The `if`
condition on the Deploy to Firebase Hosting step is using
`secrets.FIREBASE_SERVICE_ACCOUNT` directly, which is not allowed in GitHub
Actions conditional evaluation. To fix this, map the secret to an environment
variable using `env` before the step, then reference that environment variable
in the `if` condition instead of the secret. This allows the workflow to
properly evaluate the condition at runtime.

Source: Linters/SAST tools

51 changes: 51 additions & 0 deletions .github/workflows/firebase-preview.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: Firebase Hosting Preview

on:
pull_request:

permissions:
contents: read
checks: write
pull-requests: write

concurrency:
group: firebase-preview-${{ github.event.pull_request.number }}
cancel-in-progress: true

jobs:
preview:
if: ${{ github.event.pull_request.head.repo.full_name == github.repository }}
name: Build & Preview
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4
Comment on lines +22 to +23

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n .github/workflows/firebase-preview.yml | head -50

Repository: hrx01-dev/Servio

Length of output: 1961


Pin action SHAs and disable credential persistence for checkout.

Line 23 uses default credential persistence, and lines 23, 26, and 47 use mutable action refs. Pin to full commit SHAs and set persist-credentials: false on the checkout action.

Suggested hardening pattern
       - name: Checkout
-        uses: actions/checkout@v4
+        uses: actions/checkout@<full-commit-sha>
+        with:
+          persist-credentials: false

       - name: Set up Node.js
-        uses: actions/setup-node@v4
+        uses: actions/setup-node@<full-commit-sha>

       - name: Deploy Preview to Firebase Hosting
-        uses: FirebaseExtended/action-hosting-deploy@v0
+        uses: FirebaseExtended/action-hosting-deploy@<full-commit-sha>
🧰 Tools
🪛 zizmor (1.25.2)

[warning] 22-23: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[error] 23-23: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/firebase-preview.yml around lines 22 - 23, Replace the
mutable action reference `actions/checkout@v4` with its full commit SHA to
ensure supply chain security. Additionally, add the `persist-credentials: false`
parameter to the checkout action to disable default credential persistence.
Apply similar SHA pinning to any other action references on lines 26 and 47 in
the workflow file that currently use mutable version tags like `@v4` or `@v1`.

Source: Linters/SAST tools


- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: 20
cache: npm

- name: Install dependencies
run: npm ci

- name: Build
run: npm run build
env:
VITE_FIREBASE_API_KEY: ${{ secrets.VITE_FIREBASE_API_KEY }}
VITE_FIREBASE_AUTH_DOMAIN: ${{ secrets.VITE_FIREBASE_AUTH_DOMAIN }}
VITE_FIREBASE_PROJECT_ID: ${{ secrets.VITE_FIREBASE_PROJECT_ID }}
VITE_FIREBASE_STORAGE_BUCKET: ${{ secrets.VITE_FIREBASE_STORAGE_BUCKET }}
VITE_FIREBASE_MESSAGING_SENDER_ID: ${{ secrets.VITE_FIREBASE_MESSAGING_SENDER_ID }}
VITE_FIREBASE_APP_ID: ${{ secrets.VITE_FIREBASE_APP_ID }}
VITE_FIREBASE_MEASUREMENT_ID: ${{ secrets.VITE_FIREBASE_MEASUREMENT_ID }}

- name: Deploy Preview to Firebase Hosting
if: ${{ secrets.FIREBASE_SERVICE_ACCOUNT != '' }}
uses: FirebaseExtended/action-hosting-deploy@v0
with:
repoToken: ${{ secrets.GITHUB_TOKEN }}
firebaseServiceAccount: ${{ secrets.FIREBASE_SERVICE_ACCOUNT }}
projectId: ${{ secrets.VITE_FIREBASE_PROJECT_ID }}
Comment on lines +45 to +51

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

GitHub Actions secrets in if condition expression context

💡 Result:

In GitHub Actions, you cannot directly reference secrets in if conditional expressions (e.g., if: ${{ secrets.MY_SECRET == 'value' }} will not work) [1][2][3]. This is a documented limitation [1][3]. To conditionally run a job or step based on the value or presence of a secret, use one of the following workarounds: 1. Use environment variables: Define an environment variable at the job or step level using the secret, then reference that environment variable in your if conditional [1][2][4]. Since an unset secret resolves to an empty string, you can check if it is defined by checking if it is not empty [1][3][4]. jobs: example-job: runs-on: ubuntu-latest steps: - name: Run if secret is set env: MY_SECRET_VAL: ${{ secrets.MY_SECRET }} if: ${{ env.MY_SECRET_VAL!= '' }} run: echo "Secret is present" 2. Use github.secret_source: If you need to determine generally if secrets are available (for example, to prevent failures when running workflows from forks), you can use the github.secret_source context in your if condition [5][6]. This property will be 'Actions' if secrets are accessible and 'None' if they are not [6]. jobs: job1: runs-on: ubuntu-latest if: ${{ github.secret_source == 'Actions' }} steps: - run: echo "Secrets are available" 3. Use a separate job for validation: If you need to perform complex logic based on multiple secrets, you can create a dedicated "check" job that evaluates the secrets and sets an output [6]. Subsequent jobs can then use the needs context to conditionally run based on that output [6].

Citations:


🌐 Web query:

GitHub Actions expression context rules secrets available

💡 Result:

In GitHub Actions, the secrets context is used to access repository, organization, or environment secrets within a workflow run [1][2]. Key rules regarding its availability and usage in expressions include: 1. Restriction in Conditionals: You cannot directly reference secrets in if: conditionals [3][4]. If a secret is used directly in an if: expression, the condition will not function as intended because the secret's value is not exposed in that context [3]. The standard workaround is to map the secret to a job-level or step-level environment variable and then reference that environment variable within the if: conditional [3][4]. 2. Availability: The secrets context is generally available within a job, but it is not available for composite actions for security reasons [1][5]. To provide a secret to a composite action, you must pass it explicitly as an input [1][2]. 3. Empty Values: If a referenced secret has not been set, the expression will return an empty string [3]. 4. Best Practices for Expressions: While you can use ${{ secrets.SECRET_NAME }} within expressions (such as when setting environment variables or action inputs), avoid interpolating them directly into shell commands in run: blocks [3][4]. Direct interpolation can lead to secrets appearing in process lists, shell history, or logs [4]. Instead, map the secret to an environment variable and access the environment variable within your script [4]. 5. Automatic Secrets: GITHUB_TOKEN is a built-in secret automatically included in the secrets context for every workflow run [1][6]. For detailed usage, you can map secrets to environment variables as follows: env: MY_SECRET_VAR: ${{ secrets.MY_SECRET }} run:./my-script.sh # access via $MY_SECRET_VAR in the script [4]

Citations:


Replace secrets usage in the if expression.

The if condition on line 46 cannot directly reference secrets; this is a documented GitHub Actions limitation. Move the secret to an env variable and check the environment variable in the condition instead.

Suggested fix
       - name: Deploy Preview to Firebase Hosting
-        if: ${{ secrets.FIREBASE_SERVICE_ACCOUNT != '' }}
+        env:
+          FIREBASE_SERVICE_ACCOUNT: ${{ secrets.FIREBASE_SERVICE_ACCOUNT }}
+        if: ${{ env.FIREBASE_SERVICE_ACCOUNT != '' }}
         uses: FirebaseExtended/action-hosting-deploy@v0
         with:
           repoToken: ${{ secrets.GITHUB_TOKEN }}
-          firebaseServiceAccount: ${{ secrets.FIREBASE_SERVICE_ACCOUNT }}
+          firebaseServiceAccount: ${{ env.FIREBASE_SERVICE_ACCOUNT }}
           projectId: ${{ secrets.VITE_FIREBASE_PROJECT_ID }}
🧰 Tools
🪛 actionlint (1.7.12)

[error] 46-46: context "secrets" is not allowed here. available contexts are "env", "github", "inputs", "job", "matrix", "needs", "runner", "steps", "strategy", "vars". see https://docs.github.com/en/actions/learn-github-actions/contexts#context-availability for more details

(expression)

🪛 zizmor (1.25.2)

[error] 47-47: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/firebase-preview.yml around lines 45 - 51, The if
condition in the "Deploy Preview to Firebase Hosting" step is directly
referencing the secret FIREBASE_SERVICE_ACCOUNT, which violates GitHub Actions
limitations that prevent secrets from being accessed in conditional expressions.
Move the secret reference to an env variable at the job or step level, then
update the if condition to check the environment variable instead of the secret
directly to resolve this issue.

Source: Linters/SAST tools

5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,7 @@ Thumbs.db
.env.local
.env.development.local
.env.test.local
.env.production.local
.env.production.local

# Firebase
.firebase/
67 changes: 67 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,73 @@ A modern SaaS website built with React, Vite, and Tailwind CSS. This project is
npm run dev
```

## 🚀 Deployment

This project uses **Firebase Hosting** for production deployments.

### Prerequisites

- [Firebase CLI](https://firebase.google.com/docs/cli) installed globally:
```bash
npm install -g firebase-tools
```
- A Firebase project with Hosting enabled
- Firebase authentication via `firebase login`

### Environment Variables

Create a `.env` file at the project root with your Firebase configuration:

```env
VITE_FIREBASE_API_KEY=your_api_key
VITE_FIREBASE_AUTH_DOMAIN=your_project.firebaseapp.com
VITE_FIREBASE_PROJECT_ID=your_project_id
VITE_FIREBASE_STORAGE_BUCKET=your_project.firebasestorage.app
VITE_FIREBASE_MESSAGING_SENDER_ID=your_sender_id
VITE_FIREBASE_APP_ID=your_app_id
VITE_FIREBASE_MEASUREMENT_ID=your_measurement_id
```

### Manual Deployment

1. Build and deploy to production:
```bash
npm run deploy
```

2. Deploy a preview channel:
```bash
npm run deploy:preview
```

### Automated Deployment (CI/CD)

Deployments are automated via GitHub Actions:

- **Production:** Merges to `main` trigger a build and deploy to the live Firebase Hosting channel.
- **Preview:** Pull requests automatically deploy to a temporary preview URL (posted as a PR comment).
Comment on lines +76 to +77

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Clarify that preview deploys are limited to same-repository PRs.

Line 77 currently reads as all pull requests get preview URLs, but the workflow condition only allows PRs whose head branch is in this repository. A short note here will avoid contributor confusion.

Suggested wording update
-- **Preview:** Pull requests automatically deploy to a temporary preview URL (posted as a PR comment).
+- **Preview:** Pull requests from branches in this repository automatically deploy to a temporary preview URL (posted as a PR comment).
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- **Production:** Merges to `main` trigger a build and deploy to the live Firebase Hosting channel.
- **Preview:** Pull requests automatically deploy to a temporary preview URL (posted as a PR comment).
- **Production:** Merges to `main` trigger a build and deploy to the live Firebase Hosting channel.
- **Preview:** Pull requests from branches in this repository automatically deploy to a temporary preview URL (posted as a PR comment).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@README.md` around lines 76 - 77, The Preview section in the README states
that all pull requests automatically deploy to preview URLs, but this is
misleading since the workflow only allows PRs from the same repository
(excluding fork PRs). Update the Preview bullet point to explicitly clarify that
preview URLs are only generated for pull requests whose head branch is in the
same repository, not for fork pull requests. This will prevent contributor
confusion when fork-based contributions don't receive preview URLs.


To enable automated deployments, add the following secrets to your GitHub repository (`Settings > Secrets and variables > Actions`):

| Secret | Description |
|--------|-------------|
| `FIREBASE_SERVICE_ACCOUNT` | Firebase service account JSON key (see [setup guide](https://github.com/FirebaseExtended/action-hosting-deploy/blob/main/docs/service-account.md)) |
| `VITE_FIREBASE_API_KEY` | Firebase API key |
| `VITE_FIREBASE_AUTH_DOMAIN` | Firebase auth domain |
| `VITE_FIREBASE_PROJECT_ID` | Firebase project ID |
| `VITE_FIREBASE_STORAGE_BUCKET` | Firebase storage bucket |
| `VITE_FIREBASE_MESSAGING_SENDER_ID` | Firebase messaging sender ID |
| `VITE_FIREBASE_APP_ID` | Firebase app ID |
| `VITE_FIREBASE_MEASUREMENT_ID` | Firebase measurement ID |

### Firebase Project Setup

1. Update the project ID in `.firebaserc` to match your Firebase project.
2. The `firebase.json` configures:
- `dist/` as the public directory (Vite build output)
- SPA rewrites (all routes serve `index.html`)
- Cache headers for static assets

## ✨ Key Features

- **Web Development Services:** Professional development of high-performance landing pages, corporate websites, and custom SaaS applications tailored for business growth.
Expand Down
36 changes: 36 additions & 0 deletions firebase.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"hosting": {
"public": "dist",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"rewrites": [
{
"source": "**",
"destination": "/index.html"
}
],
"headers": [
{
"source": "/assets/**",
"headers": [
{
"key": "Cache-Control",
"value": "public, max-age=31536000, immutable"
}
]
},
{
"source": "**/*.@(js|css)",
"headers": [
{
"key": "Cache-Control",
"value": "public, max-age=31536000, immutable"
}
]
}
]
}
}
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
"dev": "vite --open",
"build": "vite build",
"typecheck": "tsc --noEmit",
"lint": "eslint ."
"lint": "eslint .",
"deploy": "npm run build && firebase deploy --only hosting",
"deploy:preview": "npm run build && firebase hosting:channel:deploy preview"
},
"dependencies": {
"@emotion/react": "11.14.0",
Expand Down
Loading