chore: initial project setup with documentation and design assets

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>
This commit is contained in:
2026-04-16 09:44:35 +02:00
commit 7fd03a99ba
19 changed files with 2765 additions and 0 deletions

349
docs/FIRESTORE_SETUP.md Normal file
View File

@@ -0,0 +1,349 @@
# 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