GitHub - pokharelsandeep333-commits/ShiftSentry · GitHub
Skip to content

About

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

ShiftSentry

Plan work with confidence. Track shifts, forecast weekly hours, and stay ahead of every limit.

Visit the live site



Next.js 16 React 19 TypeScript 5 Tailwind CSS v4 Supabase PostgreSQL Prisma 7 Docker

📸 Screens

Landing page

ShiftSentry landing page with the headline 'Every job, every shift, under your limit' beside lavender 3D glass art and example-week chips



Desktop view

ShiftSentry dashboard showing the weekly cap, earnings, and monthly job allocation



Mobile view

ShiftSentry dashboard on a phone



Sign in

ShiftSentry sign-in box with email, Google, and GitHub options, centred on the landing page's lavender background

Note

The dashboard images come from the app's built-in preview mode, which renders sample data when no Supabase credentials are present. The landing page and sign-in are public pages. No real user data is shown anywhere.


📖 Overview

ShiftSentry is a responsive workspace for people balancing one or more jobs. It brings scheduled shifts, completed work, pay, deductions, and weekly limits into one calm view—so users can spot a problem before it becomes one.

Hours are counted in your time zone and your week, not the server's. An overnight shift is split at local midnight and counted across both days, and every total—this week, this month, all time—is accumulated the same way, so the same shift is never worth a different amount in a different view.


✨ Features

Account protections now include explicit versioned Terms acceptance and 16+ eligibility, an account JSON export, and confirmed permanent deletion from /account. Privacy and storage disclosures are at /privacy, /terms, and /cookies. See the deduplicated screenshot audit and privacy/incident/retention operations for evidence and deployment boundaries. Cloudflare analytics is left unchanged and disclosed.

The daily security-retention workflow uses the existing protected production SUPABASE_DB_URL and removes audit entries older than 30 days, daily at 06:17 UTC. It is not a new runtime/build secret. npm run check:legal checks immutable policy snapshots; npm run licenses:generate creates dependency notices, also run automatically before development and production builds. The public /open-source-licenses page provides searchable, expandable notices; full texts load on demand from generated static files. /third-party-notices.txt remains the complete downloadable bundle. All generated catalog/notice files are ignored by Git and copied with public into the production image.

Capability Description
💼 Track multiple jobs Keep job-specific colors, pay rates, deductions, and weekly caps organized in one workspace.
📅 Plan shifts ahead Add upcoming work and see it included in projected weekly hours.
⚠️ Stay under limits Get clear warnings at 80%, 90%, and 100% of global or per-job weekly caps.
💰 Understand earnings Gross pay, tax, deductions, and net—filtered by this week, this month, the last 3 or 6 months, year to date, all time, or a custom span of months.
🧾 Keep history honest A shift remembers the rate it was worked at, so a later raise never silently reprices work you already did.
🗓️ See it on a calendar Week and month views of your shifts. Overnight shifts appear on both days and clashes are marked.
🔗 Connect Google Calendar Optional and read-only: show your Google events beside your shifts and get a warning when a new shift clashes with one. A job can also opt in to adding shifts automatically from matching Google events. Nothing is ever written to Google.
🔒 Use secure sign-in Sign in with email, Google, or GitHub through Supabase Auth. Signed out, the site's home page is a public landing page with an interactive example week.
📱 Work comfortably anywhere Responsive dashboard, mobile navigation, keyboard-accessible controls, light or dark themes, and an installable app with an offline fallback page.
🎭 Take a break Imposter, a small party word game for friends, with QR-code and link invites.

🛠️ Tech Stack

Area Technologies Used
App Framework Next.js 16 App Router, React 19, TypeScript
Styling & Interaction Tailwind CSS v4, Radix Dropdown Menu, an in-house ARIA listbox, Inter, Outfit, CSS-only motion and native View Transitions
Landing Art A Three.js scene rendered offline to WebP by scripts/render-welcome-3d.mjs; Three.js is not part of the app bundle
Data & Auth Supabase Auth, PostgreSQL, Row Level Security, @supabase/ssr, @supabase/server
Server Admin Prisma 7 with PostgreSQL
Charts & Dates Recharts, date-fns, date-fns-tz
Integrations Google Calendar API (read-only scopes), tokens encrypted with AES-256-GCM
Validation & Tests Zod, Node.js test runner via tsx, SQL suites against a throwaway Postgres in Docker
Delivery Docker, GitHub Actions, Nginx on EC2

🏗️ Architecture

flowchart LR
  Browser[Browser] --> Next[Next.js App Router]
  Next --> Actions[Server actions and route handlers]
  Browser --> Auth[Supabase Auth]
  Actions --> Database[Supabase Postgres with RLS]
  Auth --> Database
  Admin[Server-only admin operations] --> Prisma[Prisma]
  Admin --> SecretClient[Supabase secret-key client]
  Prisma --> Database
  SecretClient --> Database
  Actions -. optional, read-only .-> Google[Google Calendar API]
Loading

Note: Browser-facing features use Supabase's publishable key and Row Level Security. Prisma and the secret-key client are server-only administrative tools; neither belongs in a browser bundle.


🔐 Security Posture

  • Rules enforced twice. Weekly caps, earnings snapshots, the tax-plus-deductions ceiling, and a no-overlapping-shifts constraint are enforced in TypeScript and independently by Postgres triggers—so a direct authenticated write that skips the app is rejected too.
  • Row Level Security everywhere. Every user-facing read and write goes through a cookie-bound publishable-key client; the secret key never reaches the browser.
  • Strict CSP. A per-request nonce with 'strict-dynamic' and no 'unsafe-inline' for scripts. No external script, style, image, or font hosts—fonts are bundled, not fetched.
  • Disabled means disabled. Disabling an account is enforced by database policies, so a session token issued before the ban cannot keep writing.
  • Google access is read-only. Calendar tokens are stored encrypted and every Google call is made server-to-server. Event titles and details are never stored. The only thing kept is the start and end times of events a job has opted in to sync, which become shifts.
  • Guarded pipeline. Gitleaks secret scanning, CodeQL, a production dependency audit, and a Docker build check all gate main before a release is built. Every high or critical production advisory blocks release; malformed audit reports fail closed. Dependabot alerts and security update PRs are enabled alongside the weekly audit and CodeQL runs.

The production audit currently reports no advisories. Prisma's configuration dependency is pinned to patched deepmerge-ts 8.0.2 through a scoped override, verified with Prisma generation, validation, and a production build. The full development audit still reports five affected packages from one unpatched braces advisory (GHSA-vfj7-8cjw-p6xm) in Next.js's ESLint dependency chain. This development dependency is excluded from the production audit; it is not suppressed in the full audit.


📁 Project Structure

src/
├── app/                    App Router pages, actions, callbacks, integrations, and health route
├── components/             Dashboard, calendar, game, landing, navigation, and UI primitives
├── lib/                    Auth, Supabase, Google, validation, calculations, and types
prisma/                     Prisma schema
public/welcome/             Pre-rendered landing art and dashboard captures
scripts/                    SQL test runner, audit gate, and the landing-art renderer
supabase/migrations/        Immutable timestamped production SQL migrations
supabase/tests/             SQL suites for the triggers, policies, and grants
docs/screenshots/           Images used by this README
.github/workflows/          CI, scheduled audit, and scheduled CodeQL workflows

🚀 Local Setup

Prerequisites

  • Node.js 24 or a compatible runtime supported by Next.js 16
  • A Supabase project with email, Google, and GitHub sign-in enabled
  • Docker (only for the SQL tests or for testing the production image locally)

1. Install & Configure

git clone https://github.com/pokharelsandeep333-commits/ShiftSentry.git
cd ShiftSentry
npm install
Copy-Item .env.example .env.local

Fill in the five Supabase and admin placeholders in .env.local. The two NEXT_PUBLIC_SUPABASE_* values are safe for the browser; SUPABASE_SECRET_KEY, DATABASE_URL, and ADMIN_EMAIL_ALLOWLIST are server-only. The four GOOGLE_* values are optional and server-only: they enable the read-only Google Calendar connection, which stays off unless GOOGLE_CALENDAR_ENABLED=true. Never commit the file.

2. Initialize Database

You must apply the database schema to your Supabase project before running the app.

npx supabase login
npx supabase link --project-ref <your-project-ref>
npx supabase db push

3. Configure Supabase Auth

Set the Supabase Auth Site URL to http://localhost:3000 and add the local callback to the Redirect URL allow list:

http://localhost:3000/auth/callback

Enable Email, Google, and GitHub under Authentication → Sign In / Providers. Each OAuth provider points back to Supabase's provider callback, https://<project-ref>.supabase.co/auth/v1/callback; Supabase then redirects to this app's allowed callback.

The optional Google Calendar connection is a separate Google OAuth client, not the Supabase Google provider. Register http://localhost:3000/integrations/google/callback as its authorized redirect URI, and generate GOOGLE_TOKEN_ENCRYPTION_KEY as 32 random bytes in base64 (the command is in .env.example).

4. Verify & Run

npm run db:generate
npm run test:earnings
npm run test:auth
npm run test:game
npm run test:security
npm run test:sql
npx tsc --noEmit
npm run lint
npm run audit:production
npm run build
npm run dev

Open http://localhost:3000.

These are the same checks the pipeline runs on every pull request:

CI status

Production release verification

Merging a green PR into protected main deploys it. GitHub Actions builds an immutable sha-<commit> image, verifies and applies pending Supabase migrations, then promotes the same image to stable. EC2 Watchtower polls every 300 seconds. After the release job succeeds, verify the live health endpoint from an allowed external network until it returns status: "ok" and the exact merged commit. Allow up to ten minutes after promotion for the image pull and restart. GitHub-hosted runner requests to this endpoint receive HTTP 403, so public health verification is an operator step. A green release job confirms image promotion; the health response confirms the running deployment.

Live configuration remains in /home/ubuntu/sandeepcloud/docker-compose.yml and /home/ubuntu/sandeepcloud/nginx.conf. Runtime credentials are interpolated from /home/ubuntu/sandeepcloud/.env, owned by root:root with mode 600; run Compose through sudo so it can read that file. Watchtower's Docker Hub credentials remain in /home/ubuntu/sandeepcloud/watchtower/config/config.json, also root:root with mode 600. Nginx is the public ingress; the app has no public port mapping.

Tip

Without Supabase configuration the root route intentionally renders a read-only dashboard preview with sample data, so the app boots and is browsable before you have any credentials. With Supabase configured, a signed-out visit to / shows the public landing page instead, at the same address.


Built for clearer weeks, calmer planning, and better work-life boundaries.

About

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages