# Project export: CalTracker

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: Cal Hacks 12.0
- Tagline: Incredible app to track your fitness journey, compete with friends, keep a gallery of the foods you eat, and intelligently guestimate macronutrients with AI powered image analysis!
- Devpost: https://devpost.com/software/caltracker-cika38
- GitHub: https://github.com/AlexthePear/CalorieTracker
- Video: https://www.youtube.com/embed/U6-4qrMXV0M?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 3 GitHub contributor(s) — Alexander Peras (20 commits), Alexander Koo (17 commits), Vanessa Roque (16 commits)

## Devpost submission (written by the team)

### Inspiration

We’re fitness-focused people who care about what we eat and how we perform. Tracking nutrition was a daily habit, but manual entry was slow and inaccurate. We wanted a smarter way—one that could estimate nutritional data directly from food images while also helping people stay accountable through social features.

### What it does

CalTracker lets users authenticate, upload images of their meals, and get detailed food information automatically using Google Gemini’s image analysis. The app stores nutrition stats tied to each user and allows friends to form social groups to track progress together. It’s a mix of AI-powered food recognition, fitness tracking, and community motivation.

### How we built it

Backend: FastAPI (Python) for APIs and data management. Frontend: React for the web interface. Mobile: Swift for iOS. Dashboard: Svelte + Tauri for a lightweight, cross-platform analytics dashboard. The AI pipeline integrates directly with Google Gemini for image-based nutrition estimation. User authentication and data storage tie all the components together into a cohesive system.

### Challenges we ran into

CORS issues caused major headaches—cross-site requests between our various frontends and backend needed constant debugging. Coordinating multiple frameworks (React, Svelte, Swift, FastAPI) was tough, especially with limited frontend experience. Managing so many moving parts introduced technical debt and integration pain points.

### Accomplishments we're proud of

We aimed high and delivered something real. We tackled multiple unfamiliar technologies, built a complex multi-platform system, and made something that could actually improve people’s health. The ambition itself was a success: connecting AI, nutrition, and social accountability into one product.

### What we learned

How CORS works and how fragile it can be. The cost of technical debt when using AI-assisted coding. Time management and the importance of realistic scope. The value of teamwork and learning outside your comfort zone. We learned that growth happens at the edge of frustration.

### What's next

We’re done with this iteration—it served its purpose as a learning project. The next step is to build something better: cleaner architecture, tighter design, stronger purpose. CalTracker was a stepping stone toward future systems that are better built, better designed, and help more people. [ \text{Growth} = \frac{\text{Experience}}{\text{Comfort Zone}} ]

## README (from the GitHub repository)

# CalTracker

> Built for Cal Hacks. AI-powered meal logging from a single photo.

Watch the ▶️ Demo Video Below:

[![Watch the video](https://img.youtube.com/vi/U6-4qrMXV0M/0.jpg)](https://www.youtube.com/watch?v=U6-4qrMXV0M)

## What it does

1. You snap a photo of your meal in the iOS app (SwiftUI).
2. The photo is sent to the FastAPI backend.
3. Backend calls the Gemini API to estimate calories, protein, fat, and other macros.
4. The result is stored in Supabase (PostgreSQL).
5. The web dashboard (Svelte + Tauri desktop shell) shows:
   - today’s intake
   - meal gallery
   - progress vs goals
   - friend/leaderboard view
   - planned charts for historical stats
6. A small physical screen device mirrors the key daily stats for at-a-glance tracking.

## Features

- 📸 **Photo-based meal capture** (iOS, SwiftUI)
- 🤖 **Image → nutrition via Gemini API**
- 🗄️ **Persistent storage with Supabase/PostgreSQL**
- 📊 **Daily calorie & macro dashboard**
- 🖼️ **Meal gallery for everything you’ve eaten**
- 🧑‍🤝‍🧑 **Share progress + leaderboards**
- 📈 **Planned charts** for intake over time
- 🖥️ **Companion physical display** tied to the user’s account

## Tech Stack

**Frontend (web/dashboard)**
- Svelte
- Tauri (desktop-style container)

**Mobile**
- SwiftUI (iOS)

**Backend**
- FastAPI (Python)
- Gemini API (image analysis)

**Database**
- Redis
- Supabase
- PostgreSQL


## Detected evidence (automated analysis)

Indexed codebase: 44 recognized source files, 101 KB.
- CSS (language) — detected in the code
- FastAPI (technology) — detected in the code
- HTML (language) — detected in the code
- JavaScript (language) — detected in the code
- Python (language) — detected in the code
- React (technology) — detected in the code
- Supabase (technology) — detected in the code
- Svelte (technology) — detected in the code
- Swift (language) — detected in the code
- Tailwind CSS (technology) — detected in the code
- TypeScript (language) — detected in the code
- Google Gemini (technology) — claimed on Devpost, not found in the code
- Node.js (technology) — claimed on Devpost, not found in the code
- PostgreSQL (technology) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (64 of 64)

```
.gitignore
backend/.gitignore
backend/gemini/latency_test.py
backend/gemini/prompt.py
backend/main.py
backend/README.md
backend/requirements.txt
components
LICENSE
mobile/caltrackerapp.swift
mobile/ContentView.swift
pi-dashboard/.gitignore
pi-dashboard/.npmrc
pi-dashboard/.prettierignore
pi-dashboard/.prettierrc
pi-dashboard/bun.lock
pi-dashboard/eslint.config.js
pi-dashboard/package.json
pi-dashboard/README.md
pi-dashboard/src/app.css
pi-dashboard/src/app.d.ts
pi-dashboard/src/app.html
pi-dashboard/src/components/RadarChart.svelte
pi-dashboard/src/components/RadarChartAxes.svelte
pi-dashboard/src/components/RadarChartBackground.svelte
pi-dashboard/src/components/RadarChartLayer.svelte
pi-dashboard/src/lib/index.ts
pi-dashboard/src/lib/radarChartUtils.ts
pi-dashboard/src/routes/+layout.svelte
pi-dashboard/src/routes/+page.svelte
pi-dashboard/static/robots.txt
pi-dashboard/svelte.config.js
pi-dashboard/tsconfig.json
pi-dashboard/vite.config.ts
README.md
requirements.txt
web/.gitignore
web/build.ts
web/bun-env.d.ts
web/bun.lock
web/bunfig.toml
web/components.json
web/package.json
web/README.md
web/src/APITester.tsx
web/src/App.tsx
web/src/components/ui/button.tsx
web/src/components/ui/card.tsx
web/src/components/ui/input.tsx
web/src/components/ui/label.tsx
web/src/components/ui/select.tsx
web/src/components/ui/textarea.tsx
web/src/frontend.tsx
web/src/index.css
web/src/index.html
web/src/index.ts
web/src/lib/utils.ts
web/src/pages/Dashboard.tsx
web/src/pages/Leaderboards.tsx
web/src/pages/Login.tsx
web/src/pages/PublicProfile.tsx
web/src/pages/UserProfile.tsx
web/styles/globals.css
web/tsconfig.json
```

### Dependencies

- backend/requirements.txt: annotated-doc@==0.0.3, annotated-types@==0.7.0, anyio@==4.11.0, cachetools@==6.2.1, certifi@==2025.10.5, cffi@==2.0.0, charset-normalizer@==3.4.4, click@==8.3.0, cryptography@==46.0.3, deprecation@==2.1.0, dnspython@==2.8.0, dotenv@==0.9.9, email-validator@==2.3.0, fastapi@==0.120.0, fastapi-cli@==0.0.14, fastapi-cloud-cli@==0.3.1, google-auth@==2.41.1, google-auth-httplib2@==0.2.0, google-auth-oauthlib@==1.2.2, google-genai@==1.46.0, h11@==0.16.0, h2@==4.3.0, hpack@==4.1.0, httpcore@==1.0.9, httplib2@==0.31.0, httptools@==0.7.1, httpx@==0.28.1, hyperframe@==6.1.0, idna@==3.11, Jinja2@==3.1.6, markdown-it-py@==4.0.0, MarkupSafe@==3.0.3, mdurl@==0.1.2, multidict@==6.7.0, oauthlib@==3.3.1, packaging@==25.0, pillow@==12.0.0, postgrest@==2.22.2, propcache@==0.4.1, pyasn1@==0.6.1, pyasn1_modules@==0.4.2, pycparser@==2.23, pydantic@==2.12.3, pydantic_core@==2.41.4, Pygments@==2.19.2, PyJWT@==2.10.1, pyparsing@==3.2.5, python-dotenv@==1.1.1, python-multipart@==0.0.20, PyYAML@==6.0.3, realtime@==2.22.2, requests@==2.32.5, requests-oauthlib@==2.0.0, rich@==14.2.0, rich-toolkit@==0.15.1, rignore@==0.7.1, rsa@==4.9.1, sentry-sdk@==2.42.1, shellingham@==1.5.4, sniffio@==1.3.1, starlette@==0.48.0, storage3@==2.22.2, StrEnum@==0.4.15, supabase@==2.22.2, supabase-auth@==2.22.2, supabase-functions@==2.22.2, tenacity@==9.1.2, typer@==0.20.0, typing_extensions@==4.15.0, typing-inspection@==0.4.2, urllib3@==2.5.0, uvicorn@==0.38.0, uvloop@==0.22.1, watchfiles@==1.1.1, websockets@==15.0.1, yarl@==1.22.0
- pi-dashboard/package.json: @eslint/compat@^1.4.0, @eslint/js@^9.36.0, @sveltejs/adapter-auto@^6.1.0, @sveltejs/kit@^2.43.2, @sveltejs/vite-plugin-svelte@^6.2.0, @tailwindcss/vite@^4.1.13, @types/node@^22, autoprefixer@^10.4.21, eslint@^9.36.0, eslint-config-prettier@^10.1.8, eslint-plugin-svelte@^3.12.4, globals@^16.4.0, postcss@^8.5.6, prettier@^3.6.2, prettier-plugin-svelte@^3.4.0, prettier-plugin-tailwindcss@^0.6.14, svelte@^5.39.5, svelte-check@^4.3.2, tailwindcss@^4.1.16, typescript@^5.9.2, typescript-eslint@^8.44.1, vite@^7.1.7
- requirements.txt: annotated-doc@==0.0.3, annotated-types@==0.7.0, anyio@==4.11.0, cachetools@==6.2.1, certifi@==2025.10.5, cffi@==2.0.0, charset-normalizer@==3.4.4, click@==8.3.0, cryptography@==46.0.3, deprecation@==2.1.0, dnspython@==2.8.0, dotenv@==0.9.9, email-validator@==2.3.0, fastapi@==0.120.0, fastapi-cli@==0.0.14, fastapi-cloud-cli@==0.3.1, google-auth@==2.41.1, google-genai@==1.46.0, h11@==0.16.0, h2@==4.3.0, hpack@==4.1.0, httpcore@==1.0.9, httptools@==0.7.1, httpx@==0.28.1, hyperframe@==6.1.0, idna@==3.11, Jinja2@==3.1.6, markdown-it-py@==4.0.0, MarkupSafe@==3.0.3, mdurl@==0.1.2, multidict@==6.7.0, packaging@==25.0, pillow@==12.0.0, postgrest@==2.22.2, propcache@==0.4.1, pyasn1@==0.6.1, pyasn1_modules@==0.4.2, pycparser@==2.23, pydantic@==2.12.3, pydantic_core@==2.41.4, Pygments@==2.19.2, PyJWT@==2.10.1, python-dotenv@==1.1.1, python-multipart@==0.0.20, PyYAML@==6.0.3, realtime@==2.22.2, requests@==2.32.5, rich@==14.2.0, rich-toolkit@==0.15.1, rignore@==0.7.1, rsa@==4.9.1, sentry-sdk@==2.42.1, shellingham@==1.5.4, sniffio@==1.3.1, starlette@==0.48.0, storage3@==2.22.2, StrEnum@==0.4.15, supabase@==2.22.2, supabase-auth@==2.22.2, supabase-functions@==2.22.2, tenacity@==9.1.2, typer@==0.20.0, typing_extensions@==4.15.0, typing-inspection@==0.4.2, urllib3@==2.5.0, uvicorn@==0.38.0, uvloop@==0.22.1, watchfiles@==1.1.1, websockets@==15.0.1, yarl@==1.22.0
- web/package.json: @radix-ui/react-label@^2.1.7, @radix-ui/react-select@^2.2.6, @radix-ui/react-slot@^1.2.3, @types/bun@latest, @types/react@^19, @types/react-dom@^19, bun-plugin-tailwind@^0.1.2, class-variance-authority@^0.7.1, clsx@^2.1.1, lucide-react@^0.545.0, react@^19, react-dom@^19, tailwind-merge@^3.3.1, tailwindcss@^4.1.11, tw-animate-css@^1.4.0

### Recent commits (newest first)

- Updated readme.md
- Update Readme.md to make the video have an image thumbnail
- Update readme.md with project details
- replaced mobile expo router code with swift UI code
- update deployment
- Merge branch 'main' of github.com:AlexthePear/CalorieTracker
- !
- got rid of localhost api call
- testing
- redeploy
- deploy
- radar chart api
- redeploy
- Merge branch 'main' of github.com:AlexthePear/CalorieTracker
- goals stuff
- redploy prayge
- ah
- gg
- LOL
- fixed prompt

## Key source files (fetched from GitHub, selected and truncated for size)

### requirements.txt

```
annotated-doc==0.0.3
annotated-types==0.7.0
anyio==4.11.0
cachetools==6.2.1
certifi==2025.10.5
cffi==2.0.0
charset-normalizer==3.4.4
click==8.3.0
cryptography==46.0.3
deprecation==2.1.0
dnspython==2.8.0
dotenv==0.9.9
email-validator==2.3.0
fastapi==0.120.0
fastapi-cli==0.0.14
fastapi-cloud-cli==0.3.1
google-auth==2.41.1
google-genai==1.46.0
h11==0.16.0
h2==4.3.0
hpack==4.1.0
httpcore==1.0.9
httptools==0.7.1
httpx==0.28.1
hyperframe==6.1.0
idna==3.11
Jinja2==3.1.6
markdown-it-py==4.0.0
MarkupSafe==3.0.3
mdurl==0.1.2
multidict==6.7.0
packaging==25.0
pillow==12.0.0
postgrest==2.22.2
propcache==0.4.1
pyasn1==0.6.1
pyasn1_modules==0.4.2
pycparser==2.23
pydantic==2.12.3
pydantic_core==2.41.4
Pygments==2.19.2
PyJWT==2.10.1
python-dotenv==1.1.1
python-multipart==0.0.20
PyYAML==6.0.3
realtime==2.22.2
requests==2.32.5
rich==14.2.0
rich-toolkit==0.15.1
rignore==0.7.1
rsa==4.9.1
sentry-sdk==2.42.1
shellingham==1.5.4
sniffio==1.3.1
starlette==0.48.0
storage3==2.22.2
StrEnum==0.4.15
supabase==2.22.2
supabase-auth==2.22.2
supabase-functions==2.22.2
tenacity==9.1.2
typer==0.20.0
typing_extensions==4.15.0
typing-inspection==0.4.2
urllib3==2.5.0
uvicorn==0.38.0
uvloop==0.22.1
watchfiles==1.1.1
websockets==15.0.1
yarl==1.22.0

```

### web/package.json

```
{
  "name": "bun-react-template",
  "version": "0.1.0",
  "private": true,
  "type": "module",
  "scripts": {
    "dev": "bun --hot src/index.ts",
    "start": "NODE_ENV=production bun src/index.ts",
    "build": "bun run build.ts"
  },
  "dependencies": {
    "@radix-ui/react-label": "^2.1.7",
    "@radix-ui/react-select": "^2.2.6",
    "@radix-ui/react-slot": "^1.2.3",
    "bun-plugin-tailwind": "^0.1.2",
    "class-variance-authority": "^0.7.1",
    "clsx": "^2.1.1",
    "lucide-react": "^0.545.0",
    "react": "^19",
    "react-dom": "^19",
    "tailwind-merge": "^3.3.1"
  },
  "devDependencies": {
    "@types/react": "^19",
    "@types/react-dom": "^19",
    "@types/bun": "latest",
    "tailwindcss": "^4.1.11",
    "tw-animate-css": "^1.4.0"
  }
}

```

### pi-dashboard/package.json

```
{
	"name": "pi-dashboard",
	"private": true,
	"version": "0.0.1",
	"type": "module",
	"scripts": {
		"dev": "vite dev",
		"build": "vite build",
		"preview": "vite preview",
		"prepare": "svelte-kit sync || echo ''",
		"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
		"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
		"format": "prettier --write .",
		"lint": "prettier --check . && eslint ."
	},
	"devDependencies": {
		"@eslint/compat": "^1.4.0",
		"@eslint/js": "^9.36.0",
		"@sveltejs/adapter-auto": "^6.1.0",
		"@sveltejs/kit": "^2.43.2",
		"@sveltejs/vite-plugin-svelte": "^6.2.0",
		"@tailwindcss/vite": "^4.1.13",
		"@types/node": "^22",
		"autoprefixer": "^10.4.21",
		"eslint": "^9.36.0",
		"eslint-config-prettier": "^10.1.8",
		"eslint-plugin-svelte": "^3.12.4",
		"globals": "^16.4.0",
		"postcss": "^8.5.6",
		"prettier": "^3.6.2",
		"prettier-plugin-svelte": "^3.4.0",
		"prettier-plugin-tailwindcss": "^0.6.14",
		"svelte": "^5.39.5",
		"svelte-check": "^4.3.2",
		"tailwindcss": "^4.1.16",
		"typescript": "^5.9.2",
		"typescript-eslint": "^8.44.1",
		"vite": "^7.1.7"
	}
}

```

### backend/requirements.txt

```
annotated-doc==0.0.3
annotated-types==0.7.0
anyio==4.11.0
cachetools==6.2.1
certifi==2025.10.5
cffi==2.0.0
charset-normalizer==3.4.4
click==8.3.0
cryptography==46.0.3
deprecation==2.1.0
dnspython==2.8.0
dotenv==0.9.9
email-validator==2.3.0
fastapi-cli==0.0.14
fastapi-cloud-cli==0.3.1
fastapi==0.120.0
google-auth-httplib2==0.2.0
google-auth-oauthlib==1.2.2
google-auth==2.41.1
google-genai==1.46.0
h11==0.16.0
h2==4.3.0
hpack==4.1.0
httpcore==1.0.9
httplib2==0.31.0
httptools==0.7.1
httpx==0.28.1
hyperframe==6.1.0
idna==3.11
Jinja2==3.1.6
markdown-it-py==4.0.0
MarkupSafe==3.0.3
mdurl==0.1.2
multidict==6.7.0
oauthlib==3.3.1
packaging==25.0
pillow==12.0.0
postgrest==2.22.2
propcache==0.4.1
pyasn1_modules==0.4.2
pyasn1==0.6.1
pycparser==2.23
pydantic_core==2.41.4
pydantic==2.12.3
Pygments==2.19.2
PyJWT==2.10.1
pyparsing==3.2.5
python-dotenv==1.1.1
python-multipart==0.0.20
PyYAML==6.0.3
realtime==2.22.2
requests-oauthlib==2.0.0
requests==2.32.5
rich-toolkit==0.15.1
rich==14.2.0
rignore==0.7.1
rsa==4.9.1
sentry-sdk==2.42.1
shellingham==1.5.4
sniffio==1.3.1
starlette==0.48.0
storage3==2.22.2
StrEnum==0.4.15
supabase-auth==2.22.2
supabase-functions==2.22.2
supabase==2.22.2
tenacity==9.1.2
typer==0.20.0
typing_extensions==4.15.0
typing-inspection==0.4.2
urllib3==2.5.0
uvicorn==0.38.0
uvloop==0.22.1
watchfiles==1.1.1
websockets==15.0.1
yarl==1.22.0

```

### backend/main.py

```python
from typing import Union
from fastapi.responses import RedirectResponse
import json
import httpx
from fastapi import FastAPI, File, UploadFile, Form, HTTPException, Cookie
from pydantic import BaseModel
from supabase import create_client, Client
from datetime import datetime
from zoneinfo import ZoneInfo
from dotenv import load_dotenv
from urllib.parse import urlencode, quote_plus
from uuid import uuid1
import requests
from google import genai
from google.genai import types
from uuid import uuid4
import os
import asyncio
from fastapi.middleware.cors import CORSMiddleware

# Version: 1.3

app = FastAPI()

app.add_middleware(
    CORSMiddleware,
    allow_origins=[
        "http://localhost:3000",
        "http://localhost:5173",
        "http://localhost:5000"
    ],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

load_dotenv()

URL = os.getenv("SUPABASE_URL")
KEY = os.getenv("SUPABASE_KEY")
supabase: Client = create_client(URL, KEY)

AUTHORIZATION_URL = "https://accounts.google.com/o/oauth2/auth"
TOKEN_URL = "https://oauth2.googleapis.com/token"
USERINFO_URL = "https://www.googleapis.com/oauth2/v3/userinfo"

# Google OAuth credentials from .env
GOOGLE_CLIENT_ID = os.getenv("GOOGLE_CLIENT_ID")
GOOGLE_CLIENT_SECRET = os.getenv("GOOGLE_CLIENT_SECRET")
GOOGLE_REDIRECT_URI = os.getenv("GOOGLE_REDIRECT_URI")

prompt = """Analyze the given food image and do your best to estimate the following:
calories (kcal),
proteins (g),
fats (g),
carbs (g),
sugar (g),
fiber (g),
and satiety index (decimal number normalized from 1-10 with
10 being the highest and 1 the lowest - levels of satiety)

Return only valid JSON with no markdown. ESPECIALLY DO NOT WRAP IN JSON MARKDOWN.

Here is an example output, FOLLOW THIS FORMAT STRICTLY.:
{
    "calories": int,
    "proteins": int,
    "fats": int,
    "carbs": int,
    "sugars": int,
    "fibers": int,
    "satiety": int
}
"""

bucket = "images"

client = genai.Client()

class Macros(BaseModel):
    calories : int
    proteins: int
    carbs : int
    fats : int
    sugars: int
    fibers : int
    satiety : int

def get_authorization_url(state: str):
    params = {
        "client_id": GOOGLE_CLIENT_ID,
        "redirect_uri": GOOGLE_REDIRECT_URI,
        "state": state,
        "response_type": "code",
        "scope": "openid profile email",
        "access_type": "offline",
        "include_granted_scopes": "true",
    }
    return f"{AUTHORIZATION_URL}?{urlencode(params, quote_via=quote_plus)}"

def get_access_token(code: str):
    data = {
        "code": code,
        "client_id": GOOGLE_CLIENT_ID,
        "client_secret": GOOGLE_CLIENT_SECRET,
        "redirect_uri": GOOGLE_REDIRECT_URI,
        "grant_type": "authorization_code",
    }
    response = requests.post(TOKEN_URL, data=data)
    response.raise_for_status()  # Will raise an exception for 4xx or 5xx errors
    return response.json()

def get_user_info(access_token: str):
    headers = {
        "Authorization": f"Bearer {access_token}",
    }
    response = requests.get(USERINFO_URL, headers=headers)
    response.raise_for_status()
    return response.json()


@app.get("/")
async def root():
    return {"ok": True}

@app.get("/oauth")
async def login(state: str, session: str = None, code: str = None):     
    if session != None:
        response = supabase.table("Sessions").select("*").eq("sid", session).execute()
        if len(response.data) != 0:
            uid = response.data[0].get("uid")
            user_info = supabase.table("Users").select("*").eq("uid", uid).execute()
            resp = RedirectResponse(url=state)
            resp.set_cookie(
                key="sid", value=session,
                httponly=True, samesite="none", secure=True, path="/",
            )
            return resp

    if code == None:
        return RedirectResponse(url=get_authorization_url(state))
    
    
    access_token = get_access_token(code).get("access_token")
    #return access_token
    response = get_user_info(access_token)
    session = str(uuid1())
    uid = response.get("email")

    user_info = supabase.table("Users").select("*").eq("uid", uid).execute()
    if(len(user_info.data) == 0):
        supabase.table("Users").insert({
            "uid": uid, "username": response.get("name")}).execute()
    user_info = supabase.table("Users").select("*").eq("uid", uid).execute()
    
    supabase.table("Sessions").insert({"sid": str(session), "uid": uid}).execute()
    
    resp = RedirectResponse(url = state)
    resp.set_cookie(
        key="sid",
        value=session,
        httponly=True,
        samesite="None",   # or "None" only if you serve over HTTPS
        secure=True,     # True only when you use HTTPS
        path="/",
    )

    return resp 

@app.get("/me")
def me(sid: str | None = Cookie(default=None)):
    if not sid:
        raise HTTPException(status_code=401)
    session = supabase.table("Sessions").select("*").eq("sid", sid).execute()
    if not session.data:
        raise HTTPException(status_code=401)
    uid = session.data[0]["uid"]
    user = supabase.table("Users").select("*").eq("uid", uid).execute().data[0]
    return {"uid": uid, "username": user["username"]}


@app.post("/entry")
async def entry(
    img: UploadFile = File(...),
    uid: str = Form(...)
):
    img_content = await img.read()
    eid = str(uuid4())
    timestamp = str(datetime.now(ZoneInfo("America/Los_Angeles")))

    async def gemini():
        try:
            loop = asyncio.get_running_loop()
            resp = await loop.run_in_executor(
                None,
                lambda: client.models.generate_content(
                    model = "gemini-2.5-flash-image",
                    contents = [
                        types.Part.from_bytes(
                            data = img_content,
                            mime_type = 'image/jpeg',
                        ),
                        prompt
                    ],
                ),
            )

    
[truncated — 5808 more characters]
```

### web/src/index.ts

```typescript
import { serve } from "bun";
import index from "./index.html";

const server = serve({
  routes: {
    // Serve index.html for all unmatched routes.
    "/*": index,

    "/api/hello": {
      async GET(req) {
        return Response.json({
          message: "Hello, world!",
          method: "GET",
        });
      },
      async PUT(req) {
        return Response.json({
          message: "Hello, world!",
          method: "PUT",
        });
      },
    },

    "/api/hello/:name": async req => {
      const name = req.params.name;
      return Response.json({
        message: `Hello, ${name}!`,
      });
    },
  },

  development: process.env.NODE_ENV !== "production" && {
    // Enable browser hot reloading in development
    hmr: true,

    // Echo console logs from the browser to the server
    console: true,
  },
});

console.log(`🚀 Server running at ${server.url}`);

```

### web/src/App.tsx

```typescript
import { useState, useEffect } from "react";
import "./index.css";
import { Login } from "./pages/Login";
import { Dashboard } from "./pages/Dashboard";
import { Leaderboards } from "./pages/Leaderboards";
import { UserProfile } from "./pages/UserProfile";
import { PublicProfile } from "./pages/PublicProfile";
import { Button } from "./components/ui/button";

const API = "https://calorie-tracker-backend-puce.vercel.app";

type Page = "login" | "dashboard" | "leaderboards" | "profile" | "public-profile";

// Set to true for easy page navigation during development
const DEV_MODE = false;

export function App() {
  const [currentPage, setCurrentPage] = useState<Page>("login");
  const [username, setUsername] = useState<string>("demo_user");
  const [viewingProfileUsername, setViewingProfileUsername] = useState<string>("");

  useEffect(() => {
    (async () => {
      try {
        const r = await fetch(`${API}/me`, { credentials: "include" });
        if (r.ok) {
          const me = await r.json();
          setUsername(me.username);
          setCurrentPage("dashboard");
        }
      } catch {}
    })();
  }, []);

  const handleLogin = (user: string) => {
    setUsername(user);
    setCurrentPage("dashboard");
  };

  const handleLogout = () => {
    setUsername("");
    setCurrentPage("login");
  };

  const handleNavigate = (page: string, profileUsername?: string) => {
    if (page === "public-profile" && profileUsername) {
      setViewingProfileUsername(profileUsername);
    }
    setCurrentPage(page as Page);
  };

  // Dev mode navigation panel
  const DevNav = () => {
    if (!DEV_MODE) return null;

    return (
      <div className="fixed bottom-4 right-4 bg-gray-900 text-white p-4 rounded-lg shadow-lg z-50">
        <div className="text-xs font-bold mb-2">DEV MODE - Quick Navigation</div>
        <div className="flex gap-2 flex-wrap max-w-sm">
          <Button
            size="sm"
            variant={currentPage === "login" ? "default" : "outline"}
            onClick={() => setCurrentPage("login")}
            className={currentPage === "login" ? "" : "bg-white text-black hover:bg-gray-200"}
          >
            Login
          </Button>
          <Button
            size="sm"
            variant={currentPage === "dashboard" ? "default" : "outline"}
            onClick={() => setCurrentPage("dashboard")}
            className={currentPage === "dashboard" ? "" : "bg-white text-black hover:bg-gray-200"}
          >
            Dashboard
          </Button>
          <Button
            size="sm"
            variant={currentPage === "leaderboards" ? "default" : "outline"}
            onClick={() => setCurrentPage("leaderboards")}
            className={currentPage === "leaderboards" ? "" : "bg-white text-black hover:bg-gray-200"}
          >
            Leaderboards
          </Button>
          <Button
            size="sm"
            variant={currentPage === "profile" ? "default" : "outline"}
            onClick={() => setCurrentPage("profile")}
            className={currentPage === "profile" ? "" : "bg-white text-black hover:bg-gray-200"}
          >
            Profile
          </Button>
        </div>
      </div>
    );
  };

  if (currentPage === "login") {
    return (
      <>
        <Login />
        <DevNav />
      </>
    );
  }

  if (currentPage === "dashboard") {
    return (
      <>
        <Dashboard
          username={username}
          onNavigate={handleNavigate}
          onLogout={handleLogout}
        />
        <DevNav />
      </>
    );
  }

  if (currentPage === "leaderboards") {
    return (
      <>
        <Leaderboards
          username={username}
          onNavigate={handleNavigate}
          onLogout={handleLogout}
        />
        <DevNav />
      </>
    );
  }

  if (currentPage === "profile") {
    return (
      <>
        <UserProfile
          username={username}
          onNavigate={handleNavigate}
          onLogout={handleLogout}
        />
        <DevNav />
      </>
    );
  }

  if (currentPage === "public-profile") {
    return (
      <>
        <PublicProfile
          currentUsername={username}
          profileUsername={viewingProfileUsername}
          onNavigate={handleNavigate}
          onLogout={handleLogout}
        />
        <DevNav />
      </>
    );
  }

  return null;
}

export default App;

```

### pi-dashboard/src/lib/index.ts

```typescript
// place files you want to import through the `$lib` alias in this folder.

```

### pi-dashboard/vite.config.ts

```typescript
import tailwindcss from '@tailwindcss/vite';
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';

export default defineConfig({
	plugins: [tailwindcss(), sveltekit()]
});

```

### mobile/caltrackerapp.swift

```swift
//
//  caltrackerApp.swift
//  caltracker
//
//  Created by Alexander Peras on 10/26/25.
//

import SwiftUI

@main
struct caltrackerApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

```

[34 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]