Daily 150 is a journaling application that encourages users to write at least 150 words daily. Leveraging the power of Gemini 2.0 Flash, it automatically summarizes journal entries from the past week every Monday, providing users with a concise overview of their thoughts and experiences.
Beyond a standard CRUD application, Daily 150 was built with a strong focus on scalability, security, and robust architecture.
- Daily Word Count Goal: Encourages consistent journaling with a 150-word daily target.
- AI-Powered Summaries: Utilizes Gemini 2.0 Flash to automatically summarize weekly journal entries.
- End-to-End Encryption: Journal entries and AI-generated summaries are encrypted to ensure privacy.
- Decoupled Summary Service: Summary generation logic is isolated into a separate service for enhanced scalability and maintainability.
- Redis Queue for Batch Processing: Efficiently processes summary requests in batches via a Redis queue, managed by a Go server.
- Rate-Limited API Calls: Implements token-based rate limiting on the summarization service to respect external API constraints.
- Robust Error Handling: Incorporates retries and chunking mechanisms for graceful failure handling during API interactions.
- Chrome Extension Integration: A companion Chrome extension blocks social media access until the user completes their daily journal entry, with status cached in Redis for performance.
The Daily 150 system is designed for scalability and resilience, as illustrated in the diagram below:
- Weekly Trigger: A cron job initiates the Go server every Monday.
- Entry Collection: The Go server fetches all journal entries from the previous week from the Database.
- Task Enqueuing: Instead of direct API calls, the Go server places summary generation tasks into a Redis Queue.
- Background Processing: A dedicated Go routine (worker process) continuously pulls tasks from the Redis queue.
- Batched Processing: The worker processes user journal entries in batches to optimize API calls to the summarization service.
- Rate-Limited API Calls: The Express Server (summarization service) manages rate limits when interacting with the Gemini 2.0 Flash API, ensuring compliance and stable operation.
- Data Storage: Once generated, the summaries are securely stored back in your Database.
- Chrome Extension Interaction: The Chrome extension interacts with the Go server to check journaling status, leveraging Redis for cached responses to minimize database load.
Backend (Go Server)
- Language: Go
- Web Framework: Fiber
- Database: PostgreSQL
- ORM/Database Toolkit: GORM
- Queue: Redis
- Authentication: JWT
- Encryption: Custom End-to-End Encryption
Frontend (React App)
- Framework: React
- Build Tool: Vite
- Language: TypeScript
- Styling: Tailwind CSS
Summarization Service (Express Server)
- Language: Node.js
- Web Framework: Express.js
- AI Model Integration: Google Gemini API
- Rate Limiting: Custom token bucket implementation
Other
- Version Control: Git
- Deployment: Railway (as indicated by
0.0.0.0inapp.Listen)
Follow these instructions to set up and run the Daily 150 project on your local machine.
- Go: Install Go (version 1.20 or higher recommended)
- Node.js & npm: Install Node.js and npm (LTS version recommended)
- PostgreSQL: Install PostgreSQL
- Redis: Install Redis
- Git: Install Git
git clone https://github.com/actuallyakshat/daily-150.git
cd daily-150-
Create
.envfile: Create a file named.envin the root directory of the project and populate it with the following content. Replace placeholder values (especially for keys) with your own securely generated ones.PORT=8080 GEMINI_KEY=YOUR_GEMINI_API_KEY # Obtain from Google AI Studio API_SECRET="your_secure_api_secret_key" SUMMARY_SERVICE_URL=http://localhost:3001/api/summary # Or the deployed URL if running separately JOURNAL_ENCRYPTION_KEY="your_secure_journal_encryption_key" # Must be 32 bytes for AES-256 CRON_ACTIVATION_KEY="your_secure_cron_activation_key" SUMMARISER_KEY="your_secure_summariser_key" JWT_SECRET="your_long_and_secure_jwt_secret" # At least 256 bits (32 bytes) for HS256 DATABASE_URL=postgresql://postgres:admin@localhost:5432/daily_150 # Update if your PG setup is different COOKIE_ENCRYPTION_KEY="your_secure_cookie_encryption_key" # A 32-byte key for AES-256
Important Security Note: For
JOURNAL_ENCRYPTION_KEY,COOKIE_ENCRYPTION_KEY,API_SECRET,CRON_ACTIVATION_KEY,SUMMARISER_KEY, andJWT_SECRET, it is crucial to generate strong, random keys. For AES-256, keys should be 32 bytes (256 bits). You can generate them using tools like OpenSSL or a programming language's cryptographically secure random number generator.Example for Go:
import ( "crypto/rand" "encoding/base64" "fmt" "log" ) func generateRandomBytes(n int) ([]byte, error) { b := make([]byte, n) _, err := rand.Read(b) if err != nil { return nil, err } return b, nil } func main() { key, err := generateRandomBytes(32) // 32 bytes for AES-256 if err != nil { log.Fatal(err) } fmt.Println("Base64 encoded key:", base64.StdEncoding.EncodeToString(key)) }
-
Set up PostgreSQL Database: Ensure your PostgreSQL server is running. Create a new database named
daily_150(or whatever you've configured inDATABASE_URL).CREATE DATABASE daily_150;
-
Install Go Dependencies:
go mod tidy
-
Run Migrations: The
init()function inmain.gowill automatically run database migrations when the server starts.
-
Navigate to the client directory:
cd client -
Install Node.js Dependencies:
npm install
or
yarn install
You need to run both the Go backend and the React frontend concurrently.
-
Start the Go Backend Server: Open a new terminal, navigate to the project root (
daily-150/), and run:go run main.go
The server will start on the port specified in your
.envfile (default8080). -
Start the React Frontend Development Server: Open another terminal, navigate to the
clientdirectory (daily-150/client), and run:npm run dev
or
yarn dev
The frontend will typically start on
http://localhost:5173. -
Access the Application: Once both servers are running, open your web browser and navigate to
http://localhost:5173(or the address where your frontend is served).
Note: If you are running the summarization service locally as a separate Node.js Express app, ensure it's also running, ideally on http://localhost:3001 to match the default SUMMARY_SERVICE_URL.
While Daily 150 implements end-to-end encryption for journal entries, it's important to note that these entries are temporarily decrypted and processed by an external Large Language Model (LLM), Gemini 2.0 Flash, for summarization. Users who prioritize absolute privacy and wish to avoid any external processing of their sensitive data might have concerns.
A more privacy-conscious solution would involve running the LLM locally within the project. However, the compute requirements for hosting such a powerful model are currently beyond the scope and budget of this project. This remains a significant future goal, as we explore ways to make the system more self-sufficient and enhance user data privacy further.
