Skip to content

yenngvp/focus

Repository files navigation

FocusOn

A personal task management and focus app with PWA support for iPhone. Built with Next.js, NestJS, and PostgreSQL — fully self-hosted via Docker with HTTPS served through Tailscale.


Screenshots

Tasks screen dark mode
Focus session modal
Focus session modal

Features

  • Task management — create, edit, delete tasks with priority levels, due dates, reminder times, categories, and subtasks
  • Focus Sessions — Pomodoro-style timer with 10 tick sound options and adjustable duration (1–90 min)
  • Dark / Light theme — toggleable from Settings, persists across sessions with no flash on load
  • Accent color picker — 6 colors (Focus Blue, Violet, Teal, Emerald, Rose, Amber) applied system-wide
  • User profile — name and email stored in PostgreSQL, survives app restarts
  • PWA — installable on iPhone via Safari, service worker caches shell assets
  • Daily cleanup — cron job deletes completed tasks from previous days at midnight; shows warning for overdue uncompleted tasks on load
  • HTTPS via Tailscale — served over a valid TLS certificate, reachable from any network the device is on

Tech Stack

Layer Technology
Frontend Next.js 14 (App Router), React 18, Mantine UI v7, TypeScript
Backend NestJS 10, TypeORM, Passport JWT, @nestjs/schedule
Database PostgreSQL 16
Reverse proxy nginx (TLS termination, HTTP→HTTPS redirect)
Containers Podman / Docker Compose
PWA Service Worker, Web App Manifest, viewport-fit=cover
HTTPS Tailscale HTTPS certificates

Project Structure

focuson/
├── backend/                  # NestJS REST API (port 3001)
│   └── src/
│       ├── auth/             # JWT authentication
│       ├── tasks/            # Task CRUD + overdue query
│       ├── subtasks/         # Subtask management
│       ├── categories/       # Task categories
│       ├── settings/         # Theme, accent color, notification prefs
│       ├── profile/          # User profile (name, email)
│       └── scheduler/        # Daily midnight cleanup cron
├── frontend/                 # Next.js app (port 3000)
│   └── src/
│       ├── app/
│       │   ├── login/
│       │   ├── tasks/        # Task list + focus session
│       │   └── settings/     # Profile, theme, accent, categories
│       ├── components/
│       │   ├── AppLayout.tsx       # Mobile bottom nav + desktop sidebar
│       │   ├── TaskCard.tsx
│       │   ├── FocusSessionModal.tsx
│       │   ├── ThemeProvider.tsx   # Dark/light + accent CSS vars
│       │   └── ServiceWorkerRegistrar.tsx
│       └── lib/
│           ├── api.ts         # Axios API client
│           └── auth.ts        # localStorage auth helpers
├── nginx/
│   ├── nginx.conf             # Reverse proxy + TLS config
│   └── certs/                 # Tailscale TLS certificate + key
└── docker-compose.yml

Quick Start

Prerequisites

  • Podman or Docker with Compose plugin

1. Configure the API URL

Edit docker-compose.yml. Under frontend.build.args, set your server address:

args:
  NEXT_PUBLIC_API_URL: http://<YOUR-LAN-IP>:3001/api

For HTTPS (required for PWA service workers), see the Tailscale section below.

2. Build and run

podman compose up --build -d

3. Login

Field Value
Username alphatrix
Password alphatrix$

HTTPS with Tailscale (for iPhone PWA)

Service workers require HTTPS. Tailscale provides free, automatic certificates for your machine.

# 1. Install Tailscale and connect your machine + iPhone to the same tailnet
# 2. Issue a certificate
tailscale cert your-machine-name.your-tailnet.ts.net

# 3. Copy certs into the project
mkdir -p nginx/certs
cp your-machine-name.*.crt nginx/certs/
cp your-machine-name.*.key nginx/certs/

# 4. Update nginx/nginx.conf — replace the server_name and cert filenames
# 5. Update docker-compose.yml frontend build arg:
#    NEXT_PUBLIC_API_URL: https://your-machine-name.your-tailnet.ts.net/api

# 6. Rebuild
podman compose up --build -d

Cert renewal: Tailscale certs expire every 90 days. Re-run tailscale cert ..., copy the new files, then podman compose restart nginx.


Install on iPhone

  1. Open Safari on your iPhone (Chrome cannot install PWAs on iOS)
  2. Go to https://your-tailscale-domain
  3. Tap ShareAdd to Home ScreenAdd

The app launches fullscreen with proper notch and home-indicator handling.


API Reference

All endpoints require Authorization: Bearer <token> except /api/auth/login.

Method Path Description
POST /api/auth/login Authenticate, returns JWT
GET /api/profile Get user profile
PUT /api/profile Update name / email
GET /api/tasks List all tasks
POST /api/tasks Create task
GET /api/tasks/overdue Get uncompleted past-due tasks
GET /api/tasks/:id Get task by ID
PUT /api/tasks/:id Update task
PATCH /api/tasks/:id/complete Toggle completion
DELETE /api/tasks/:id Delete task
POST /api/tasks/:taskId/subtasks Add subtask
PATCH /api/subtasks/:id Update subtask
DELETE /api/subtasks/:id Delete subtask
GET /api/categories List categories
POST /api/categories Create category
PUT /api/categories/:id Update category
DELETE /api/categories/:id Delete category
GET /api/settings Get user settings
PUT /api/settings Update settings

Database

PostgreSQL 16, running in Docker with a persistent named volume (postgres_data).

Host:     localhost
Port:     5432
Database: curator
Username: postgres
Password: postgres

Connect:

# From host
psql -h localhost -U postgres -d curator

# Inside container
podman exec -it curator-postgres psql -U postgres -d curator

Tables created automatically by TypeORM on first start:

Table Description
tasks Tasks with priority, due date, reminder
subtasks Subtasks linked to tasks
task_categories Join table
categories Categories with color
user_settings Theme, accent color, notification prefs
user_profile User name and email

Environment Variables

Backend (docker-compose.ymlbackend.environment)

Variable Default Description
DB_HOST postgres PostgreSQL hostname
DB_PORT 5432 PostgreSQL port
DB_USERNAME postgres DB user
DB_PASSWORD postgres DB password
DB_DATABASE curator DB name
JWT_SECRET (change this) JWT signing secret
PORT 3001 API server port

Frontend (build-time arg)

Variable Description
NEXT_PUBLIC_API_URL Full URL to the backend API, e.g. https://host/api

Local Development

Backend

cd backend
npm install
npm run start:dev   # runs on http://localhost:3001

Frontend

cd frontend
npm install
NEXT_PUBLIC_API_URL=http://localhost:3001/api npm run dev   # runs on http://localhost:3000

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages