Add project foundation: CLAUDE.md, requirements tracking system, technical architecture docs, Firestore setup guide, device testing guide, and Stitch design mockups for Precision Vitality app. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
350 lines
9.9 KiB
Markdown
350 lines
9.9 KiB
Markdown
# Guida Configurazione Firebase & Firestore
|
||
|
||
> Guida passo-passo per configurare Firebase, Firestore e Cloud Functions per CalorieTracker.
|
||
> Ultimo aggiornamento: 16/04/2026
|
||
|
||
---
|
||
|
||
## 1. Creazione Progetto Firebase
|
||
|
||
### Passo 1 — Console Firebase
|
||
1. Andare su [console.firebase.google.com](https://console.firebase.google.com)
|
||
2. Cliccare "Aggiungi progetto"
|
||
3. Nome progetto: `calorie-tracker` (o simile disponibile)
|
||
4. **Disabilitare** Google Analytics (non necessario per ora)
|
||
5. Cliccare "Crea progetto"
|
||
|
||
### Passo 2 — Aggiungere App Web
|
||
1. Nella dashboard progetto, cliccare l'icona **Web** (`</>`)
|
||
2. Nome app: `CalorieTracker Web`
|
||
3. **Non** abilitare Firebase Hosting (non necessario)
|
||
4. Copiare la configurazione Firebase:
|
||
```javascript
|
||
const firebaseConfig = {
|
||
apiKey: "AIza...",
|
||
authDomain: "calorie-tracker-XXXXX.firebaseapp.com",
|
||
projectId: "calorie-tracker-XXXXX",
|
||
storageBucket: "calorie-tracker-XXXXX.appspot.com",
|
||
messagingSenderId: "123456789",
|
||
appId: "1:123456789:web:abcdef"
|
||
};
|
||
```
|
||
5. Salvare questi valori in `environment.ts` e `environment.prod.ts`
|
||
|
||
---
|
||
|
||
## 2. Abilitare Firestore
|
||
|
||
### Passo 1 — Creare Database
|
||
1. Nel menu laterale Firebase: **Build → Firestore Database**
|
||
2. Cliccare "Crea database"
|
||
3. Selezionare località: **europe-west1 (Belgio)** — più vicino all'Italia
|
||
4. Selezionare "Inizia in modalità produzione"
|
||
5. Cliccare "Abilita"
|
||
|
||
### Passo 2 — Regole di Sicurezza
|
||
Nella tab **Regole** di Firestore, incollare:
|
||
|
||
```
|
||
rules_version = '2';
|
||
|
||
service cloud.firestore {
|
||
match /databases/{database}/documents {
|
||
|
||
// Nessun accesso di default
|
||
match /{document=**} {
|
||
allow read, write: if false;
|
||
}
|
||
|
||
// Accesso pasti: solo utente proprietario
|
||
match /users/{userId}/meals/{mealId} {
|
||
allow read, write: if request.auth != null
|
||
&& request.auth.uid == userId;
|
||
|
||
// Validazione scrittura
|
||
allow create: if request.auth != null
|
||
&& request.auth.uid == userId
|
||
&& request.resource.data.calories is number
|
||
&& request.resource.data.calories > 0
|
||
&& request.resource.data.calories <= 9999
|
||
&& request.resource.data.inputType in ['manual', 'llm']
|
||
&& request.resource.data.timestamp is timestamp
|
||
&& request.resource.data.createdAt is timestamp;
|
||
|
||
allow update: if request.auth != null
|
||
&& request.auth.uid == userId;
|
||
|
||
allow delete: if request.auth != null
|
||
&& request.auth.uid == userId;
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### Passo 3 — Indici
|
||
Nella tab **Indici** di Firestore, creare indice composto:
|
||
|
||
| Collection | Campi | Query Scope |
|
||
|------------|-------|-------------|
|
||
| `users/{userId}/meals` | `timestamp` DESC | Collection |
|
||
|
||
> **Nota**: Firestore creerà automaticamente gli indici necessari quando l'app esegue le prime query. In alternativa, il file `firestore.indexes.json` nel progetto definisce gli indici programmaticamente.
|
||
|
||
---
|
||
|
||
## 3. Abilitare Authentication
|
||
|
||
### Passo 1 — Anonymous Auth
|
||
1. Nel menu laterale: **Build → Authentication**
|
||
2. Cliccare "Inizia"
|
||
3. Tab **Metodo di accesso**
|
||
4. Abilitare **Anonimo** → switch ON → Salva
|
||
|
||
### Passo 2 — (Futuro) Google Sign-In
|
||
> Per upgrade futuro da Anonymous a Google Sign-In:
|
||
> 1. Abilitare provider "Google" in Authentication
|
||
> 2. Configurare OAuth consent screen in Google Cloud Console
|
||
> 3. Implementare linking account (da anonimo a Google)
|
||
|
||
---
|
||
|
||
## 4. Configurazione App Android
|
||
|
||
### Passo 1 — Aggiungere App Android
|
||
1. Dashboard Firebase → "Aggiungi app" → icona Android
|
||
2. Package name: `com.precisionvitality.app` (deve corrispondere a `capacitor.config.ts`)
|
||
3. App nickname: `CalorieTracker Android`
|
||
4. SHA-1: (opzionale per ora, necessario per Google Sign-In)
|
||
|
||
### Passo 2 — Scaricare google-services.json
|
||
1. Scaricare `google-services.json`
|
||
2. Copiare in `android/app/google-services.json` (dopo `npx cap add android`)
|
||
|
||
---
|
||
|
||
## 5. Configurazione App iOS
|
||
|
||
### Passo 1 — Aggiungere App iOS
|
||
1. Dashboard Firebase → "Aggiungi app" → icona iOS
|
||
2. Bundle ID: `com.precisionvitality.app`
|
||
3. App nickname: `CalorieTracker iOS`
|
||
|
||
### Passo 2 — Scaricare GoogleService-Info.plist
|
||
1. Scaricare `GoogleService-Info.plist`
|
||
2. Copiare in `ios/App/App/GoogleService-Info.plist` (dopo `npx cap add ios`)
|
||
|
||
---
|
||
|
||
## 6. Setup Firebase Cloud Functions (Proxy AI)
|
||
|
||
### Passo 1 — Upgrade a Blaze Plan (Pay-as-you-go)
|
||
> **ATTENZIONE**: Le Cloud Functions richiedono il piano Blaze (pay-as-you-go).
|
||
> Il piano Blaze include comunque il tier gratuito di Firestore e Auth.
|
||
> Non ci saranno costi se il traffico resta nel free tier.
|
||
|
||
1. Console Firebase → icona ingranaggio → Utilizzo e fatturazione
|
||
2. Upgrade a Blaze
|
||
3. Impostare budget alert: $5/mese
|
||
|
||
### Alternativa gratuita: Se non si vuole il piano Blaze
|
||
- Usare un backend NestJS su VPS esistente come proxy
|
||
- Oppure usare Cloudflare Workers (free tier: 100k req/giorno)
|
||
|
||
### Passo 2 — Inizializzare Cloud Functions
|
||
```bash
|
||
# Nella root del progetto
|
||
npm install -g firebase-tools
|
||
firebase login
|
||
firebase init functions
|
||
|
||
# Selezionare:
|
||
# - Linguaggio: TypeScript
|
||
# - ESLint: Sì
|
||
# - Installare dipendenze: Sì
|
||
```
|
||
|
||
### Passo 3 — Configurare Secret per API Key
|
||
```bash
|
||
# Salvare API key come secret (non in codice!)
|
||
firebase functions:secrets:set ANTHROPIC_API_KEY
|
||
# Inserire: sk-ant-...
|
||
```
|
||
|
||
### Passo 4 — Implementare la Function
|
||
File `functions/src/index.ts`:
|
||
|
||
```typescript
|
||
import { onRequest } from 'firebase-functions/v2/https';
|
||
import { defineSecret } from 'firebase-functions/params';
|
||
import Anthropic from '@anthropic-ai/sdk';
|
||
|
||
const anthropicKey = defineSecret('ANTHROPIC_API_KEY');
|
||
|
||
export const estimateCalories = onRequest(
|
||
{
|
||
cors: true,
|
||
region: 'europe-west1',
|
||
secrets: [anthropicKey],
|
||
timeoutSeconds: 15,
|
||
memory: '256MiB',
|
||
},
|
||
async (req, res) => {
|
||
// Verificare metodo POST
|
||
if (req.method !== 'POST') {
|
||
res.status(405).send('Method Not Allowed');
|
||
return;
|
||
}
|
||
|
||
// Verificare auth token
|
||
const authHeader = req.headers.authorization;
|
||
if (!authHeader?.startsWith('Bearer ')) {
|
||
res.status(401).send('Unauthorized');
|
||
return;
|
||
}
|
||
|
||
// Estrarre e validare input
|
||
const { description } = req.body;
|
||
if (!description || typeof description !== 'string' || description.length > 500) {
|
||
res.status(400).send('Invalid description');
|
||
return;
|
||
}
|
||
|
||
try {
|
||
const client = new Anthropic({ apiKey: anthropicKey.value() });
|
||
|
||
const message = await client.messages.create({
|
||
model: 'claude-haiku-4-5-20251001',
|
||
max_tokens: 256,
|
||
system: `Sei un nutrizionista. Stima le calorie del pasto descritto.
|
||
Rispondi SOLO con JSON: {"calories": number, "confidence": "high"|"medium"|"low", "explanation": "string"}`,
|
||
messages: [{ role: 'user', content: description }],
|
||
});
|
||
|
||
// Parsare risposta
|
||
const text = message.content[0].type === 'text' ? message.content[0].text : '';
|
||
const jsonStr = text.replace(/```json?\n?/g, '').replace(/```/g, '').trim();
|
||
const result = JSON.parse(jsonStr);
|
||
|
||
res.json(result);
|
||
} catch (error) {
|
||
console.error('Estimation error:', error);
|
||
res.status(500).json({ error: 'Estimation failed' });
|
||
}
|
||
}
|
||
);
|
||
```
|
||
|
||
### Passo 5 — Deploy
|
||
```bash
|
||
cd functions
|
||
npm install @anthropic-ai/sdk
|
||
firebase deploy --only functions
|
||
```
|
||
|
||
---
|
||
|
||
## 7. Integrazione Angular
|
||
|
||
### Installare dipendenze
|
||
```bash
|
||
npm install @angular/fire firebase
|
||
```
|
||
|
||
### Configurare in app.config.ts (Angular 17+ standalone)
|
||
```typescript
|
||
import { provideFirebaseApp, initializeApp } from '@angular/fire/app';
|
||
import { provideFirestore, getFirestore, enableIndexedDbPersistence } from '@angular/fire/firestore';
|
||
import { provideAuth, getAuth } from '@angular/fire/auth';
|
||
import { environment } from '../environments/environment';
|
||
|
||
export const appConfig: ApplicationConfig = {
|
||
providers: [
|
||
provideFirebaseApp(() => initializeApp(environment.firebase)),
|
||
provideFirestore(() => {
|
||
const firestore = getFirestore();
|
||
enableIndexedDbPersistence(firestore);
|
||
return firestore;
|
||
}),
|
||
provideAuth(() => getAuth()),
|
||
// ... altri providers
|
||
]
|
||
};
|
||
```
|
||
|
||
---
|
||
|
||
## 8. File di Configurazione Locale
|
||
|
||
### `firestore.rules` (nella root del progetto)
|
||
Copiare le regole dal Passo 2 della Sezione 2.
|
||
|
||
### `firestore.indexes.json`
|
||
```json
|
||
{
|
||
"indexes": [
|
||
{
|
||
"collectionGroup": "meals",
|
||
"queryScope": "COLLECTION",
|
||
"fields": [
|
||
{ "fieldPath": "timestamp", "order": "DESCENDING" }
|
||
]
|
||
}
|
||
],
|
||
"fieldOverrides": []
|
||
}
|
||
```
|
||
|
||
### `.firebaserc`
|
||
```json
|
||
{
|
||
"projects": {
|
||
"default": "calorie-tracker-XXXXX"
|
||
}
|
||
}
|
||
```
|
||
|
||
### `firebase.json`
|
||
```json
|
||
{
|
||
"firestore": {
|
||
"rules": "firestore.rules",
|
||
"indexes": "firestore.indexes.json"
|
||
},
|
||
"functions": {
|
||
"source": "functions",
|
||
"runtime": "nodejs18"
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 9. Limiti Free Tier Firebase (Spark / Blaze)
|
||
|
||
| Risorsa | Limite Gratuito | Note |
|
||
|---------|----------------|------|
|
||
| Firestore letture | 50.000/giorno | ~1.600 utenti × 30 letture/giorno |
|
||
| Firestore scritture | 20.000/giorno | ~2.000 utenti × 10 pasti/giorno |
|
||
| Firestore storage | 1 GiB | Sufficiente per ~5M documenti pasto |
|
||
| Auth utenti | Illimitati | Anonymous + email + social |
|
||
| Cloud Functions invocazioni | 2M/mese | ~66.000/giorno |
|
||
| Cloud Functions compute | 400.000 GB-secondi/mese | Sufficiente per proxy AI |
|
||
|
||
---
|
||
|
||
## 10. Checklist Configurazione
|
||
|
||
- [ ] Progetto Firebase creato
|
||
- [ ] Firestore abilitato (europe-west1)
|
||
- [ ] Regole sicurezza configurate
|
||
- [ ] Anonymous Auth abilitato
|
||
- [ ] App Web registrata + config copiata
|
||
- [ ] App Android registrata + google-services.json scaricato
|
||
- [ ] (Opzionale) App iOS registrata + GoogleService-Info.plist scaricato
|
||
- [ ] Cloud Functions inizializzate
|
||
- [ ] ANTHROPIC_API_KEY salvata come secret
|
||
- [ ] Cloud Function deployata
|
||
- [ ] @angular/fire installato e configurato
|
||
- [ ] Test lettura/scrittura funzionante
|
||
- [ ] Offline persistence verificata
|