Skip to content

aphonogelia/diary

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

18 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

diary-app

A full-stack mobile journaling app for tracking mood over time β€” built solo from scratch with React Native, Expo, and Supabase.

Users can log daily entries, browse their history in a calendar or list view, visualize mood trends with live stats, and personalize their profile. Authentication is handled via OAuth (GitHub / Google) with secure, per-user data enforced at the database level through Row Level Security.

Screen Recording

Features

  • πŸ“… Calendar view β€” browse past entries by date
  • πŸ“‹ List view β€” scrollable entry history
  • πŸ“Š Mood stats β€” percentage breakdown of moods over time
  • πŸ‘€ Customizable profile β€” username, full name, avatar upload
  • πŸ” OAuth authentication β€” GitHub & Google via Supabase Auth
  • πŸ”’ Row Level Security β€” users only ever see their own data

Stack

Layer Technology
Framework React Native 0.81 + Expo SDK 54
Routing Expo Router (file-based)
Language TypeScript
Backend Supabase (Auth, PostgreSQL, Storage)
Auth OAuth 2.0 β€” GitHub & Google
Deployment EAS Build (Android APK)

Prerequisites

  • Node.js
  • EAS CLI (npm install -g eas-cli)
  • ADB installed and available in your PATH
  • Android Studio with a Pixel 6 AVD configured (optional β€” only needed if using the emulator)

Quick Start

# First time β€” full native compile (~2–5 min)
make build

# Daily β€” Metro bundler only (APK already installed)
make dev

# Physical device or tunnel needed
make tunnel

Make Commands

Every day

Command Description
make build Compile native Android code, install APK, start Metro
make dev Start Metro only β€” no recompile (use daily)

Other

Command Description
make studio Boot Android emulator manually
make tunnel Metro with tunnel (physical devices)
make web Expo web
make install Install JS dependencies
make lint Run ESLint
make depcheck Check for unused dependencies
make pics Push assets to emulator gallery

Cleanup (least β†’ most destructive)

Command What it removes
make clean node_modules
make clean-build Android build output (~700MB)
make clean-android Entire android/ folder
make clean-cache Metro/Expo cache
make clean-emulator Wipes emulator data
make fclean All of the above + package-lock.json

Nuclear reset

make re   # fclean + reinstall + prebuild + build

Project Structure

app/
β”œβ”€β”€ _layout.tsx          ← root layout with auth guard
β”œβ”€β”€ index.tsx            ← returns null, lets layout handle routing
β”œβ”€β”€ (auth)/
β”‚   β”œβ”€β”€ _layout.tsx      ← minimal <Slot />
β”‚   └── landing.tsx
└── (app)/
    β”œβ”€β”€ _layout.tsx      ← minimal <Slot />
    └── diary.tsx

Auth Flow

Uses Supabase OAuth (GitHub / Google) with a custom dev build β€” Expo Go cannot handle custom URI schemes.

const redirectTo = makeRedirectUri({ native: 'diaryapp://' })

Supabase redirect URLs to configure in the dashboard (Authentication β†’ URL Configuration):

diaryapp://
exp://*/*
http://localhost:8081

Database

Schema

create table public.profiles (
  id         uuid references auth.users(id) on delete cascade primary key,
  username   text,
  avatar_url text,
  full_name  text,
  created_at timestamptz default now(),
  updated_at timestamptz default now()
);

create table public.entries (
  id         uuid default gen_random_uuid() primary key,
  user_id    uuid references public.profiles(id) on delete cascade not null,
  title      text not null,
  content    text,
  mood       text,
  created_at timestamptz default now(),
  updated_at timestamptz default now()
);

RLS

Row Level Security means you never need to manually pass user_id in queries β€” Supabase reads auth.uid() from the JWT on every request.

CREATE POLICY "users see own entries"
ON entries FOR SELECT
USING (auth.uid() = user_id);

Views

-- Mood breakdown as percentages
CREATE OR REPLACE VIEW mood_percentages AS
WITH mood_counts AS (
  SELECT mood, COUNT(*) AS count
  FROM entries
  WHERE mood IS NOT NULL AND mood != ''
  GROUP BY mood
),
total AS (
  SELECT COUNT(*) AS total_count
  FROM entries
  WHERE mood IS NOT NULL AND mood != ''
)
SELECT mood, count,
  ROUND((count::numeric / total_count) * 100, 2) AS percentage
FROM mood_counts, total
ORDER BY percentage DESC;

-- Total entries per user
CREATE OR REPLACE VIEW user_entry_stats AS
SELECT user_id, COUNT(*) AS total_entries
FROM entries
GROUP BY user_id;

-- Make views respect RLS
ALTER VIEW mood_percentages SET (security_invoker = true);
ALTER VIEW user_entry_stats SET (security_invoker = true);

Android Testing

Option A β€” Direct APK install (no emulator needed)

Build the APK remotely via EAS:

eas build --profile development --platform android

Download the .apk from expo.dev, then install it directly on your phone or emulator:

adb install /path/to/your-build.apk

Then start Metro:

make dev      # or: make tunnel for physical device

Option B β€” Emulator (compile locally)

make build    # first time (~2–5 min)
make dev      # daily

Physical Android device (USB)

  1. Settings β†’ About phone β†’ tap Build number 7 times
  2. Settings β†’ Developer options β†’ enable USB debugging
  3. Plug in via USB
  4. adb devices β€” confirm it's listed
  5. Either install the APK via adb install or run make build (Expo will ask which target)

iOS

iOS requires macOS + Xcode. On Linux, use EAS cloud build:

npx eas build --platform ios --profile development

Requires an Apple Developer account ($99/year). Install via TestFlight.

Environment

EXPO_PUBLIC_SUPABASE_URL=...
EXPO_PUBLIC_SUPABASE_ANON_KEY=...

Expo requires the EXPO_PUBLIC_ prefix for client-side env vars.


Supabase Client

import { createClient } from '@supabase/supabase-js'
import AsyncStorage from '@react-native-async-storage/async-storage'

export const supabase = createClient(
  process.env.EXPO_PUBLIC_SUPABASE_URL!,
  process.env.EXPO_PUBLIC_SUPABASE_ANON_KEY!,
  { auth: { storage: AsyncStorage } }
)

AsyncStorage is required β€” React Native has no localStorage, so without it the session dies on unmount.

About

A mood journaling app built with React Native and Expo. Track your emotional patterns with a clean, minimal interface designed for daily reflection.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors