diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..0609e87 --- /dev/null +++ b/.env.example @@ -0,0 +1,13 @@ +# Firebase Configuration +VITE_FIREBASE_API_KEY=your_api_key_here +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 + +# Add other API keys as needed +# VITE_STRIPE_PUBLIC_KEY=pk_test_... +# VITE_GOOGLE_MAPS_API_KEY=AIza... +# VITE_API_BASE_URL=https://api.example.com \ No newline at end of file diff --git a/.github/workflows/firebase-hosting-merge.yml b/.github/workflows/firebase-hosting-merge.yml index 63d7b44..9e132ea 100644 --- a/.github/workflows/firebase-hosting-merge.yml +++ b/.github/workflows/firebase-hosting-merge.yml @@ -11,7 +11,27 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - run: npm ci && npm run build + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Build with environment variables + 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 }} + - uses: FirebaseExtended/action-hosting-deploy@v0 with: repoToken: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/firebase-hosting-pull-request.yml b/.github/workflows/firebase-hosting-pull-request.yml index 3257a2d..b854ec6 100644 --- a/.github/workflows/firebase-hosting-pull-request.yml +++ b/.github/workflows/firebase-hosting-pull-request.yml @@ -13,7 +13,27 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - run: npm ci && npm run build + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Build with environment variables + 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 }} + - uses: FirebaseExtended/action-hosting-deploy@v0 with: repoToken: ${{ secrets.GITHUB_TOKEN }} diff --git a/ENVIRONMENT_SETUP.md b/ENVIRONMENT_SETUP.md new file mode 100644 index 0000000..b975421 --- /dev/null +++ b/ENVIRONMENT_SETUP.md @@ -0,0 +1,107 @@ +# Environment Variables Setup + +This project uses environment variables to securely manage API keys and configuration values. + +## ๐Ÿ  Local Development + +### Manual Setup + +Create a `.env.local` file in the project root with your Firebase configuration: + +```bash +# .env.local +VITE_FIREBASE_API_KEY=your_api_key_here +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 +``` + +### Steps: + +1. **Copy the template** from `.env.example` or use the values above +2. **Create `.env.local`** in your project root +3. **Paste the configuration** values +4. **Start development**: `npm run dev` + +## ๐Ÿš€ Production Deployment (GitHub Actions) + +For production deployment, add these secrets to your GitHub repository: + +### Step 1: Go to GitHub Secrets +Navigate to: https://github.com/MarioLJFerreira/mini-dragme/settings/secrets/actions + +### Step 2: Add Repository Secrets + +Click "New repository secret" and add each of these: + +| Secret Name | Value | +|-------------|-------| +| `VITE_FIREBASE_API_KEY` | `your_api_key_here` | +| `VITE_FIREBASE_AUTH_DOMAIN` | `your_project.firebaseapp.comm` | +| `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` | + +### Step 3: Verify Setup + +1. **Local testing**: Run `npm run dev` - should work with `.env.local` +2. **Production testing**: Push to main branch - GitHub Actions will use the secrets + +## โž• Adding New Environment Variables + +### For Local Development: +Add to `.env.local`: +```bash +VITE_YOUR_NEW_API_KEY=your_development_key_here +``` + +### For Production: +1. Add the secret to GitHub repository secrets +2. Update both GitHub Actions workflows to include the new environment variable: +```yaml +env: + VITE_YOUR_NEW_API_KEY: ${{ secrets.VITE_YOUR_NEW_API_KEY }} +``` + +### In Your Code: +```javascript +// Use the environment variable in your React components +const apiKey = import.meta.env.VITE_YOUR_NEW_API_KEY; +``` + +## ๐Ÿ”’ Security Notes + +- โœ… **Local development**: Uses `.env.local` (not committed to git) +- โœ… **Production**: Uses GitHub repository secrets (encrypted) +- โœ… **No hardcoded secrets** in your codebase +- โœ… **Vite automatically** includes `VITE_` prefixed variables in the build + +## ๐Ÿงช Testing + +```bash +# Test locally +npm run dev + +# Test build process +npm run build + +# Check if environment variables are loaded (in browser console) +console.log(import.meta.env.VITE_FIREBASE_API_KEY); +``` + +## ๐Ÿ’ก Why VITE_ Prefix? + +Vite only exposes environment variables that start with `VITE_` to your client-side code for security reasons. This prevents accidentally exposing sensitive server-side variables to the browser. + +## โœ… Benefits of This Approach + +- **Simple**: No complex setup or external dependencies +- **Secure**: Secrets are encrypted in GitHub repository secrets +- **Standard**: Industry-standard approach for environment variables +- **Scalable**: Easy to add more secrets as needed +- **Team-friendly**: Clear documentation for all developers \ No newline at end of file diff --git a/README.md b/README.md index 3de9d88..43514ce 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,13 @@ To get a local copy up and running, follow these simple steps. ```sh npm install ``` -4. Run the development server: +4. Set up environment variables: + ```sh + # Copy the example file and add your Firebase configuration + cp .env.example .env.local + # Edit .env.local with your Firebase values (see ENVIRONMENT_SETUP.md) + ``` +5. Run the development server: ```sh npm run dev ``` @@ -67,58 +73,66 @@ The project is structured to be modular and scalable, with clear separation of c ``` mini-dragme/ โ”‚ +โ”œโ”€โ”€ .env.example # Environment variables template for development setup. +โ”œโ”€โ”€ .env.local # Local environment variables (not committed to git). +โ”œโ”€โ”€ .firebaserc # Firebase project configuration. +โ”œโ”€โ”€ .gitignore # Git ignore rules for the project. +โ”œโ”€โ”€ ENVIRONMENT_SETUP.md # Guide for setting up environment variables. +โ”œโ”€โ”€ eslint.config.js # ESLint configuration for code quality. +โ”œโ”€โ”€ firebase.json # Firebase hosting and Firestore configuration. +โ”œโ”€โ”€ firestore.indexes.json # Firestore database indexes configuration. +โ”œโ”€โ”€ firestore.rules # Firestore security rules. โ”œโ”€โ”€ index.html # Main HTML entry point for the Vite application. โ”œโ”€โ”€ package.json # Project dependencies and scripts configuration. โ”œโ”€โ”€ package-lock.json # Locked versions of dependencies for consistent installs. -โ”œโ”€โ”€ vite.config.js # Vite build tool configuration. -โ”œโ”€โ”€ .gitignore # Git ignore rules for the project. -โ”œโ”€โ”€ eslint.config.js # ESLint configuration for code quality. โ”œโ”€โ”€ README.md # Project documentation and setup instructions. +โ”œโ”€โ”€ vite.config.js # Vite build tool configuration. +โ”‚ +โ”œโ”€โ”€ .github/ # GitHub configuration and workflows. +โ”‚ โ””โ”€โ”€ workflows/ # GitHub Actions CI/CD workflows. +โ”‚ โ”œโ”€โ”€ firebase-hosting-merge.yml # Deploy to production on main branch. +โ”‚ โ””โ”€โ”€ firebase-hosting-pull-request.yml # Deploy preview on pull requests. +โ”‚ +โ”œโ”€โ”€ public/ # Static assets served directly by the web server. +โ”‚ โ”œโ”€โ”€ 404.html # Custom 404 error page. +โ”‚ โ”œโ”€โ”€ index.html # Firebase hosting welcome page. +โ”‚ โ””โ”€โ”€ vite.svg # Vite logo. โ”‚ โ””โ”€โ”€ src/ # Source code directory. โ”‚ โ”œโ”€โ”€ assets/ # Static images, icons, and logos. - โ”‚ โ””โ”€โ”€ logo.svg # App's logo. + โ”‚ โ”œโ”€โ”€ logo.svg # App's logo. + โ”‚ โ””โ”€โ”€ react.svg # React logo. โ”‚ โ”œโ”€โ”€ components/ # Reusable UI components. - โ”‚ โ”œโ”€โ”€ ui/ # Small, foundational UI elements. - โ”‚ โ”‚ โ”œโ”€โ”€ Button.jsx # All button types (primary, secondary, danger). - โ”‚ โ”‚ โ”œโ”€โ”€ Input.jsx # Input fields for forms, search, etc. - โ”‚ โ”‚ โ”œโ”€โ”€ Modal.jsx # Modal component for creating/editing tasks or projects. - โ”‚ โ”‚ โ”œโ”€โ”€ Tag.jsx # Visual component for task tags/categories. - โ”‚ โ”‚ โ””โ”€โ”€ Avatar.jsx # User profile image component. - โ”‚ โ”‚ + โ”‚ โ”œโ”€โ”€ auth/ # Authentication-related components. + โ”‚ โ”œโ”€โ”€ board/ # Core components for the drag-and-drop board. โ”‚ โ”œโ”€โ”€ layout/ # Structural components for the application's layout. - โ”‚ โ”‚ โ”œโ”€โ”€ Header.jsx # Top navigation bar. - โ”‚ โ”‚ โ”œโ”€โ”€ Sidebar.jsx # Side navigation for project lists, filters, etc. - โ”‚ โ”‚ โ””โ”€โ”€ MainContent.jsx # The main container for the board area. - โ”‚ โ”‚ - โ”‚ โ””โ”€โ”€ board/ # Core components for the drag-and-drop board. - โ”‚ โ”œโ”€โ”€ Board.jsx # The main container for the entire board. - โ”‚ โ”œโ”€โ”€ BoardColumn.jsx # Represents a single column/list in the board. This component will contain the Droppable logic. - โ”‚ โ”œโ”€โ”€ TaskCard.jsx # A single task card component. This component will contain the Draggable logic. - โ”‚ โ”œโ”€โ”€ AddTaskCard.jsx # A button/form for adding new tasks to a column. - โ”‚ โ””โ”€โ”€ ColumnHeader.jsx # Component for the column title, settings, and menu. + โ”‚ โ””โ”€โ”€ ui/ # Small, foundational UI elements. โ”‚ - โ”œโ”€โ”€ pages/ # Page-level components that compose the application's views. - โ”‚ โ”œโ”€โ”€ Dashboard.jsx # The main landing page after login. - โ”‚ โ”œโ”€โ”€ Login.jsx # The user login page. - โ”‚ โ”œโ”€โ”€ Register.jsx # The user registration page. - โ”‚ โ””โ”€โ”€ ProjectView.jsx # The primary component for a single project board. + โ”œโ”€โ”€ context/ # React Context API for global state management. + โ”‚ โ”œโ”€โ”€ AuthContext.jsx # Manages authentication state across the app. + โ”‚ โ”œโ”€โ”€ BoardContext.jsx # Manages the state for the current board (tasks, columns, etc.). + โ”‚ โ””โ”€โ”€ ThemeContext.jsx # Manages the light/dark mode theme. + โ”‚ + โ”œโ”€โ”€ firebase/ # Firebase configuration and utilities. + โ”‚ โ”œโ”€โ”€ auth.js # Firebase authentication utilities. + โ”‚ โ””โ”€โ”€ firebase.js # Firebase app initialization and configuration. โ”‚ โ”œโ”€โ”€ hooks/ # Custom React hooks for shared logic. โ”‚ โ”œโ”€โ”€ useAuth.js # Handles user authentication state and logic. โ”‚ โ””โ”€โ”€ useDarkMode.js # Manages dark mode state and local storage. โ”‚ - โ”œโ”€โ”€ context/ # React Context API for global state management. - โ”‚ โ”œโ”€โ”€ AuthContext.jsx # Manages authentication state across the app. - โ”‚ โ”œโ”€โ”€ ThemeContext.jsx # Manages the light/dark mode theme. - โ”‚ โ””โ”€โ”€ BoardContext.jsx # Manages the state for the current board (tasks, columns, etc.). - โ”‚ โ”œโ”€โ”€ lib/ # Utility functions and helper modules. โ”‚ โ”œโ”€โ”€ api.js # Functions for making API calls to the backend. โ”‚ โ””โ”€โ”€ dndHelpers.js # Helper functions for the drag-and-drop logic (e.g., reordering arrays). โ”‚ + โ”œโ”€โ”€ pages/ # Page-level components that compose the application's views. + โ”‚ โ”œโ”€โ”€ Dashboard.jsx # The main landing page after login. + โ”‚ โ”œโ”€โ”€ Login.jsx # The user login page. + โ”‚ โ”œโ”€โ”€ ProjectView.jsx # The primary component for a single project board. + โ”‚ โ””โ”€โ”€ Register.jsx # The user registration page. + โ”‚ โ”œโ”€โ”€ styles/ # Tailwind CSS Modules for component-specific styling. โ”‚ โ”œโ”€โ”€ buttons.module.css โ”‚ โ”œโ”€โ”€ cards.module.css @@ -126,9 +140,8 @@ mini-dragme/ โ”‚ โ”œโ”€โ”€ layout.module.css โ”‚ โ””โ”€โ”€ tags.module.css โ”‚ - โ”œโ”€โ”€ App.jsx # The root component that renders the application's pages. โ”œโ”€โ”€ App.css # Main application styles. - โ”œโ”€โ”€ index.jsx # The entry point for the React application. + โ”œโ”€โ”€ App.jsx # The root component that renders the application's pages. โ”œโ”€โ”€ index.css # Global CSS styles and Tailwind imports. โ”œโ”€โ”€ main.jsx # Main entry point that renders the React app. โ””โ”€โ”€ tailwind.config.js # Configuration for Tailwind CSS. @@ -141,6 +154,9 @@ mini-dragme/ - **React DnD (@hello-pangea/dnd):** The core drag-and-drop logic will be implemented with this library. The `Draggable` and `Droppable` components will be primarily placed within `TaskCard.jsx` and `BoardColumn.jsx`, respectively. - **Drag Logic:** Reordering and moving functions will be housed in `lib/dndHelpers.js` for clean separation and reusability. - **Board State:** The state of the board (tasks, columns, etc.) will be managed within a combination of `BoardContext.jsx` and the `pages/ProjectView.jsx` component to ensure a single source of truth. + - **Firebase Integration:** Authentication and real-time data are handled through Firebase, with configuration managed via environment variables for security. + - **Environment Variables:** All sensitive configuration (API keys, Firebase config) is managed through environment variables with `VITE_` prefix for client-side access. + - **CI/CD Pipeline:** Automated deployment to Firebase Hosting via GitHub Actions on every push to main branch and preview deployments for pull requests. ----- diff --git a/on b/on deleted file mode 100644 index 9702e14..0000000 --- a/on +++ /dev/null @@ -1,88 +0,0 @@ -diff --git a/package-lock.json b/package-lock.json -index 0e5235b..0503787 100644 ---- a/package-lock.json -+++ b/package-lock.json -@@ -8,6 +8,7 @@ - "name": "mini-dragme", - "version": "0.0.0", - "dependencies": { -+ "@google-cloud/secret-manager": "^6.1.0", - "firebase": "^12.1.0", - "react": "^19.1.1", - "react-dnd": "^16.0.1", -@@ -1536,6 +1537,18 @@ - "integrity": "sha512-6m8+P+dE/RPl4OPzjTxcTbQ0rGeRyeTvAi9KwIffBVCiAMKrfXfLZaqD1F+m8t4B5/Q5aHsMozOgirkH1F5oMQ==", - "license": "Apache-2.0" - }, -+ "node_modules/@google-cloud/secret-manager": { -+ "version": "6.1.0", -+ "resolved": "https://registry.npmjs.org/@google-cloud/secret-manager/-/secret-manager-6.1.0.tgz", -+ "integrity": "sha512-IrXjT1z2yW98htydkopcxdhNVh4rpAzO3oTVzKymfdnzmzCKWVxhfwYWWvIor1bzgQN4sa21Wv0CMDokJyTt7A==", -+ "license": "Apache-2.0", -+ "dependencies": { -+ "google-gax": "^5.0.0" -+ }, -+ "engines": { -+ "node": ">=18" -+ } -+ }, - "node_modules/@grpc/grpc-js": { - "version": "1.9.15", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.9.15.tgz", -@@ -1672,6 +1685,16 @@ - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, -+ "node_modules/@js-sdsl/ordered-map": { -+ "version": "4.4.2", -+ "resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz", -+ "integrity": "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==", -+ "license": "MIT", -+ "funding": { -+ "type": "opencollective", -+ "url": "https://opencollective.com/js-sdsl" -+ } -+ }, - "node_modules/@protobufjs/aspromise": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", -@@ -2041,6 +2064,15 @@ - "win32" - ] - }, -+ "node_modules/@tootallnate/once": { -+ "version": "2.0.0", -+ "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", -+ "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", -+ "license": "MIT", -+ "engines": { -+ "node": ">= 10" -+ } -+ }, - "node_modules/@types/babel__core": { - "version": "7.20.5", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", -@@ -2282,6 +2314,18 @@ - "url": "https://opencollective.com/vitest" - } - }, -+ "node_modules/abort-controller": { -+ "version": "3.0.0", -+ "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", -+ "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", -+ "license": "MIT", -+ "dependencies": { -+ "event-target-shim": "^5.0.0" -+ }, -+ "engines": { -+ "node": ">=6.5" -+ } -+ }, - "node_modules/acorn": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", -@@ -2305,6 +2349,15 @@ - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, -+ "node_modules/a \ No newline at end of file diff --git a/src/App.jsx b/src/App.jsx index 1a51650..9b45f6e 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,6 +1,6 @@ import { useState } from 'react' import reactLogo from './assets/react.svg' -import viteLogo from '/vite.svg' +import viteLogo from './assets/vite.svg' import './App.css' import { SignInButton, SignUpButton, LogOutButton } from './components/auth/Button' import { SignInForm, SignUpForm } from './components/auth/Input' diff --git a/src/assets/vite.svg b/src/assets/vite.svg new file mode 100644 index 0000000..e7b8dfb --- /dev/null +++ b/src/assets/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/firebase/firebase.js b/src/firebase/firebase.js index c5a145d..a07d063 100644 --- a/src/firebase/firebase.js +++ b/src/firebase/firebase.js @@ -8,13 +8,13 @@ import { getAuth } from "firebase/auth"; // Your web app's Firebase configuration // For Firebase JS SDK v7.20.0 and later, measurementId is optional const firebaseConfig = { - apiKey: "AIzaSyCalE6UBEP6X3ZX7R19tC5VoKO03wgAoTo", - authDomain: "dragme-mini.firebaseapp.com", - projectId: "dragme-mini", - storageBucket: "dragme-mini.firebasestorage.app", - messagingSenderId: "188367279980", - appId: "1:188367279980:web:a554ae85ce559846fac549", - measurementId: "G-2XEQ97DMV8" + apiKey: import.meta.env.VITE_FIREBASE_API_KEY, + authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN, + projectId: import.meta.env.VITE_FIREBASE_PROJECT_ID, + storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET, + messagingSenderId: import.meta.env.VITE_FIREBASE_MESSAGING_SENDER_ID, + appId: import.meta.env.VITE_FIREBASE_APP_ID, + measurementId: import.meta.env.VITE_FIREBASE_MEASUREMENT_ID }; // Initialize Firebase