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