Project LifeOps (Part 3): Core Interactive Modules: Fitness, Library, Cinema, and Professional Kanba

Project LifeOps (Part 3): Core Interactive Modules: Fitness, Library, Cinema, and Professional Kanba

Leader 1 21 102
calendar_today agoschedule5 min read
— Originally published at datalaria.com

In earlier installments, we engineered the foundational backbone of LifeOps: in Part 1 we designed the polymorphic PostgreSQL schema and modular FastAPI backend, and in Part 2 we brought the Glassmorphism Dark Mode design system and global 360° Dashboard to life.

Now comes the most defining phase of development: the day-to-day functional modules.

A personal operating system fails if it forces users into rigid input forms or scatters daily data across disconnected views. The challenge was articulating three completely disparate life areas under unified design and performance standards:

  1. 🏃 Health & Physical Fitness: Workout logging across sports with dynamic metrics (distance volume, calories, pace calculations, and Personal Bests).
  2. 📚 Intellectual Culture & Media: Book tracking with interactive reading progress bars and an entertainment catalog organized by streaming platform.
  3. 💼 Professional Execution: An agile 4-column Kanban board mapped to projects, equipped with a chronological progress log powered by PostgreSQL JSONB.

[!TIP]
Test the live app: You can explore the production build of LifeOps directly at https://datalaria.com/apps/lifeops/.


🗺️ LifeOps Series Roadmap

To understand how every architectural layer fits together, this series spans 5 structured installments:

  1. 🟢 Part 1: Personal Operating System Architecture and FastAPI + Supabase Backend
  2. 🟢 Part 2: React Frontend with Glassmorphism, 360° Dashboard, and Design System
  3. 🟢 Part 3 (This article): Core Interactive Modules: Fitness, Library, Cinema, and Professional Kanban Board
  4. Part 4: In-Memory Word Dossiers (.docx) & Multi-Sheet Excel Engine (.xlsx)
  5. Part 5: 24/7 Zero-Cost Cloud Deployment ($0/month), Mobile UX, and PWA

1. The UX Dilemma: Dual View Mode (Inspiring Cards vs. Synthesized Table) 🎴📊

When building data-intensive dashboards, designers face a classic user experience tradeoff:

  • The Grid / Cards View: Visually engaging, spacious, and inspiring. It highlights book covers, movie posters, and workout chips at a glance.
  • The Data Table View: Irreplaceable when auditing timestamps, comparing heart rates, or scanning through an entire month of logs without endless vertical scrolling.

Instead of forcing a single opinionated view, I built a persistent dual-mode toggle stored in localStorage:

const [viewMode, setViewMode] = useState(() => {
  return localStorage.getItem('lifeops_view_sport') || 'grid';
});

const handleViewChange = (mode) => {
  setViewMode(mode);
  localStorage.setItem('lifeops_view_sport', mode);
};

In the header of each module, two unobtrusive buttons with LayoutGrid and Table icons toggle the presentation mode instantly. Thanks to React and Vite's build architecture, view switches execute in sub-milliseconds without triggering redundant server roundtrips.

Dual view mode in LifeOps: Synthesized data table with key metrics, personal bests, and instant sorting


2. Fitness & Performance Module (SportModule.jsx) 🏃💨

The fitness module caters to multi-sport athletes practicing running, road cycling, gym strength sessions, and swimming.

Fitness and Performance Module featuring aggregate KPI summary widgets and detailed workout cards

┌────────────────────────────────────────────────────────────────────────┐
│  🏃 Sport & Fitness                    [ + Log Workout ]       [⊞|≡]   │
├─────────────────┬─────────────────┬─────────────────┬──────────────────┤
│ TOTAL DISTANCE  │ ACTIVE TIME     │ CALORIES        │ PERSONAL BESTS   │
│   142.5 km      │   18.4 hours    │   12,450 kcal   │    4 PBs 🏅      │
├─────────────────┴─────────────────┴─────────────────┴──────────────────┤
│                                                                        │
│ ┌───────────────────────────┐         ┌──────────────────────────────┐ │
│ │ 🏃 RUNNING         🏅 PB  │         │ 🚴 CYCLING                   │ │
│ │ Sunday Long Run           │         │ Mountain Pass Century Ride   │ │
│ │ 2026-09-10                │         │ 2026-09-08                   │ │
│ │ [📍 21.1 km] [⏱️ 1h 48m]  │         │ [📍 65.0 km] [⏱️ 2h 45m]     │ │
│ │ [🔥 1,420 kcal] [❤️ 152bpm]│        │ [🔥 1,890 kcal] [⛰️ +950m]    │ │
│ └───────────────────────────┘         └──────────────────────────────┘ │
└────────────────────────────────────────────────────────────────────────┘
2.1. Aggregated High-Level KPIs

Before rendering individual activity items, we compute cumulative totals using in-memory array reducers:

const totalKm = workouts.reduce((sum, act) => sum + (act.workout?.distance_km || 0), 0);
const totalMinutes = workouts.reduce((sum, act) => sum + (act.duration_minutes || 0), 0);
const totalCalories = workouts.reduce((sum, act) => sum + (act.workout?.calories || 0), 0);
const pbCount = workouts.filter((act) => act.workout?.personal_best).length;
2.2. Segregated FastAPI Payload

When an athlete records an exercise, the client dispatches a structured contract that FastAPI parses into the master table lifeops.activities and the child table lifeops.workouts:

const payload = {
  activity: {
    activity_type: 'sport',
    title: formData.title,
    date: formData.date,
    duration_minutes: parseInt(formData.duration_minutes),
    description: formData.notes,
  },
  workout: {
    workout_type: formData.workout_type, // 'running' | 'cycling' | 'gym'
    distance_km: parseFloat(formData.distance_km) || null,
    calories: parseInt(formData.calories) || null,
    avg_heart_rate: parseInt(formData.avg_heart_rate) || null,
    elevation_m: parseInt(formData.elevation_m) || null,
    personal_best: formData.personal_best,
    notes: formData.notes,
  },
};

This ensures shared attributes (dates, general durations, notes) remain globally indexable for the 360° Dashboard, while biometric attributes (elevation gain, heart rate, personal bests) reside in their specialized child table with cascading foreign key guarantees.


3. Culture & Media Tracking: Books & Cinema 📚🎬

For cultural tracking, the goal was leaving behind fragmented mobile notes in favor of an enriched visual library.

3.1. Interactive Reading Progress (BooksModule.jsx)

On each book card, we calculate page completion percentages in real time:

const percentage = b.pages_total > 0 
  ? Math.min(100, Math.round((b.pages_read / b.pages_total) * 100)) 
  : 0;

<div className="book-progress-wrapper">
  <div className="progress-info">
    <span>{b.pages_read} / {b.pages_total} pages</span>
    <span className="percentage-tag">{percentage}%</span>
  </div>
  <div className="progress-bar-bg">
    <div 
      className="progress-bar-fill" 
      style={{ 
        width: `${percentage}%`,
        background: percentage === 100 ? 'var(--accent-emerald)' : 'var(--grad-primary)'
      }} 
    />
  </div>
</div>

A status filter organizes titles into reading, completed, and wishlist, paired with an interactive 5-star rating system using lucide-react icons.

Reading Library module with dynamic progress tracking percentages and status badges

3.2. Streaming Media Catalog (FilmsModule.jsx)

The cinema module tracks movies, TV series, and documentaries cataloged by streaming provider (Netflix, HBO Max, Prime Video, Disney+, Cinema). Each entry logs release year, director, rating, and personal review notes, answering: "What were the best films I watched this past quarter?".

Cinema and TV series catalog organized by streaming provider with ratings


4. Professional Execution: The Kanban Board (KanbanBoard.jsx) 📋

For professional tasks, I implemented a full Kanban board featuring 4 columns reflecting agile task lifecycles:

  1. 📝 To Do (todo): Backlog tasks queued for upcoming execution.
  2. In Progress (in_progress): Active work during the current sprint.
  3. 🔍 In Review (review): Tasks pending review, testing, or third-party feedback.
  4. Done (done): Completed deliverables.

Professional 4-column Kanban board with project tags, urgent priority chips, and progress badges

┌──────────────────┬──────────────────┬──────────────────┬──────────────────┐
│ 📝 TO DO (3)     │ ⚡ IN PROGRESS (2)│ 🔍 IN REVIEW (1) │ ✅ DONE (8)      │
├──────────────────┼──────────────────┼──────────────────┼──────────────────┤
│ ┌──────────────┐ │ ┌──────────────┐ │ ┌──────────────┐ │ ┌──────────────┐ │
│ │ Refactor API │ │ │ Frontend UI  │ │ │ E2E Test Run │ │ │ DB Migration │ │
│ │ 🚨 Critical  │ │ │ 🟡 Medium    │ │ │ 🟢 Low       │ │ │ 2026-09-02   │ │
│ │ 📅 Sep 18    │ │ │ 💬 3 notes   │ │ │ 📅 Today     │ │ │ 💬 5 notes   │ │
│ │ [→ Move]     │ │ │ [←]      [→] │ │ │ [←]      [→] │ │ │ [← Move]     │ │
│ └──────────────┘ │ └──────────────┘ │ └──────────────┘ │ └──────────────┘ │
└──────────────────┴──────────────────┴──────────────────┴──────────────────┘
4.1. Optimistic UI Updates for Tactile Fluidity

When moving a task from in_progress to review, waiting for the entire roundtrip (browser → Render API → Supabase → response) introduces an undesirable delay of several hundred milliseconds.

To deliver an instantaneous tactile feel, we execute an optimistic state update in React:

const handleMoveTask = async (taskId, currentStatus, direction) => {
  const statusOrder = ['todo', 'in_progress', 'review', 'done'];
  const currentIndex = statusOrder.indexOf(currentStatus);
  const targetIndex = direction === 'next' ? currentIndex + 1 : currentIndex - 1;

  if (targetIndex < 0 || targetIndex >= statusOrder.length) return;
  const targetStatus = statusOrder[targetIndex];

  // 1. Instantaneous optimistic update

1 Comment

2 votes
🔥 Join developers growing publicly
Share your knowledge, build in public, and grow your developer presence with a global community.

More Posts

Dashboard Operasional Armada Rental Mobil dengan Python + FastAPI

Masbadar - Mar 12

Project LifeOps (Part 1): Personal Operating System Architecture and FastAPI + Supabase Backend

Datalaria - Sep 10

Project LifeOps (Part 2): React Frontend with Glassmorphism, 360° Dashboard, and Dark Mode Design Sy

Datalaria - Sep 13

Building an AI Product Backend From Scratch: FastAPI, Postgres, pgvector, Stripe, and What I'd Do Di

Luis Cruz - May 17

Core Web Vitals Benchmarks for Shopify Stores (2026 Data)

ApogeeWatcherverified - Sep 16
chevron_left
5.8k Points124 Badges
Spaindatalaria.com
56Posts
16Comments
20Connections
Digital Logbook: Data, AI, Tech, and the Industry.

Telecom Eng, MBA & Big Data in Defense & Securit... Show more

Related Jobs

View all jobs →

Commenters (This Week)

2 comments
1 comment
1 comment

Contribute meaningful comments to climb the leaderboard and earn badges!