Skip to content

Konfigurering

📋 Environment Variables

.env.local (Development & Production)

# Firebase SDK Configuration
VITE_FIREBASE_API_KEY=AIzaSyCy1o9u8bZkWNMuRVPT_qIzPyrtnWLX52Q
VITE_FIREBASE_PROJECT_ID=gkit-meeting-suite
VITE_FIREBASE_AUTH_DOMAIN=gkit-meeting-suite.firebaseapp.com
VITE_FIREBASE_STORAGE_BUCKET=gkit-meeting-suite.firebasestorage.app
VITE_FIREBASE_MESSAGING_SENDER_ID=390932420298
VITE_FIREBASE_APP_ID=1:390932420298:web:4f3b99bf122a5bb9534633

# Optional: Gemini AI Integration
VITE_GEMINI_API_KEY=your_gemini_api_key_here

Hent Firebase config:

firebase apps:sdkconfig web

Sikkerhet: .env.local er gitignore'd - inneholder bare klient-API-nøkler (ikke hemmeligheter)

🔥 Firebase Configuration

.firebaserc (Project Mapping)

{
  "projects": {
    "default": "gkit-meeting-suite"
  }
}

firebase.json (Services Config)

{
  "hosting": {
    "public": "dist",
    "ignore": ["firebase.json", "**/.*", "**/node_modules/**"],
    "rewrites": [
      {
        "source": "**",
        "destination": "/index.html"
      }
    ]
  },
  "functions": {
    "source": "functions",
    "codebase": "default",
    "runtime": "nodejs20"
  },
  "firestore": {
    "rules": "firestore.rules",
    "indexes": "firestore.indexes.json"
  },
  "emulators": {
    "auth": { "port": 9099 },
    "functions": { "port": 5001 },
    "firestore": { "port": 8080 },
    "storage": { "port": 9199 },
    "hosting": { "port": 5000 },
    "pubsub": { "port": 8085 },
    "ui": { "enabled": true, "port": 4000 }
  }
}

🔐 Firestore Security Rules

firestore.rules

Definerer lese/skrive-tilgang for hver collection:

// Helper function: Autentisert bruker?
function isAuthenticated() {
  return request.auth != null;
}

// Helper: Er bruker medlem?
function isMember(userId) {
  return exists(/databases/$(database)/documents/members/$(userId));
}

// Helper: Kan bruker stemme?
function canVote() {
  return isAuthenticated() && 
         isMember(request.auth.uid) &&
         get(/databases/$(database)/documents/members/$(request.auth.uid)).data.canVote == true;
}

// Members: Bare lese eget dokument
match /members/{document=**} {
  allow read: if isAuthenticated() && request.auth.uid == document;
  allow write: if false; // Importeres via Cloud Function
}

// Agenda: Alle kan lese, bare admins kan skrive
match /agenda/{document=**} {
  allow read: if isAuthenticated();
  allow write: if isAuthenticated() && request.auth.token.admin == true;
}

// Speakers: Autentiserte kan opprette og lese
match /speakers/{document=**} {
  allow create: if isAuthenticated();
  allow read: if isAuthenticated();
  allow write: if false;
}

// Votes: Anonym stemmegivning, aldri lesbart
match /votes/{document=**} {
  allow create: if canVote();
  allow read, write: if false;
}

// Vote receipts: Prevent double voting
match /vote_receipts/{userId} {
  allow read: if isAuthenticated() && request.auth.uid == userId;
  allow create: if isAuthenticated() && 
                request.auth.uid == userId &&
                !exists(/databases/$(database)/documents/vote_receipts/$(userId));
}

Deploy rules:

firebase deploy --only firestore:rules

🎨 TypeScript Configuration

tsconfig.json

{
  "compilerOptions": {
    "target": "ES2020",
    "useDefineForClassFields": true,
    "lib": ["ES2020", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "skipLibCheck": true,
    "strict": false,              // Relaxed for rapid development
    "noUnusedLocals": false,      // Allow unused variables
    "noUnusedParameters": false,
    "noFallthroughCasesInSwitch": true,
    "types": ["vite/client"]      // Vite env variables
  },
  "include": ["src", "index.tsx"],
  "references": [{ "path": "./tsconfig.node.json" }]
}

⚠️ Merk: strict: false brukes for rask utvikling. Bør settes til true før produksjon.

🚀 Vite Build Configuration

vite.config.ts

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react-swc'

export default defineConfig({
  plugins: [react()],
  server: {
    port: 3000,
    open: true
  },
  build: {
    target: 'ES2020',
    outDir: 'dist'
  }
})

Build kommandoer:

npm run dev       # Dev server med hot reload
npm run build     # Production build
npm run preview   # Preview production build lokalt

🔄 Development vs Production

Development

  • Vite dev server (hot module reload)
  • TypeScript strict checking disabled
  • Source maps for debugging
  • Firestore emulator (optional)

Production

  • Optimert bundle (tree-shaking)
  • Minified + gzipped (347 KB)
  • Source maps excluded
  • Real Firebase (europe-north1)

📦 Package.json Scripts

{
  "scripts": {
    "dev": "vite",
    "build": "tsc && vite build",
    "preview": "vite preview",
    "lint": "eslint . --ext ts,tsx --report-unused-disable-directives",
    "type-check": "tsc --noEmit"
  }
}

🌍 Miljøer

production (gkit-meeting-suite.web.app)

  • Skarp Firebase database (europe-north1)
  • Real members data
  • Real voting data
  • CloudFlare CDN caching

staging (planned)

  • Separate Firebase project
  • Test members data
  • For pre-release testing

development (localhost:3000)

  • Local Firestore emulator (if running)
  • Mock data for UI testing
  • TypeScript strict disabled

Bytt miljø via .firebaserc eller firebase use PROJECT_ID