TreeMap
A free, open-source disk-space visualizer. Squarified treemap, duplicate hunting, disk-full forecasting, and cleanup that only ever moves files to the Trash.
A private networking tracker for students recruiting for internships. Keep your contacts in a spreadsheet-style grid and book calls on a weekly calendar.
ProductivityTypeScript · CSSGitHub @tfinn18OnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Cover your network. A private networking tracker and call calendar for students recruiting for internships.
Taken from the repository README
Loading the full README.
Read the full README ↗Coverage is a list for your recruiting season: every banker, alum, and recruiter you’re talking to, where each conversation stands, and the calls on your calendar.
Cover your network. A private networking tracker for college students recruiting for internships: a spreadsheet-style contact grid plus a weekly call calendar.
Live demo: https://coverage-green.vercel.app · sign up free, then click Try with example data.
| Import from LinkedIn, with a review step | Book calls on a weekly calendar |
|---|---|
Connections.csv from LinkedIn's data export (or any tracker CSV), or paste profile URLs. Every
import goes through an editable review table that skips duplicates.All free tiers; no paid APIs.
| Layer | Choice |
|---|---|
| Framework | Next.js 16 (App Router, Cache Components) · React 19 · TypeScript |
| Styling | Tailwind CSS v4 with design tokens · IBM Plex Sans/Mono + Source Serif 4 |
| Auth + database | Supabase: Auth (email, Google OAuth) and Postgres with Row Level Security |
| Calendar | FullCalendar v6 (MIT core: timeGrid + interaction) |
| PDF parsing | pdf.js (pdfjs-dist), lazy-loaded, runs in the browser |
| Testing | Vitest (unit + RLS isolation) · Playwright + axe-core (end-to-end + accessibility) |
| CI / hosting | GitHub Actions · Vercel Hobby |
flowchart LR
subgraph Browser
UI["React UI<br/>Contacts grid · Calendar · Import"]
PDF["pdf.js<br/>(profile PDFs never leave the browser)"]
SBC["Supabase JS client<br/>(publishable key only)"]
UI --> PDF
UI --> SBC
end
subgraph Vercel["Vercel (Next.js)"]
PX["proxy.ts<br/>refresh session cookie,<br/>guard /contacts /calls /account"]
RH["Route handlers<br/>/auth/callback · /auth/confirm · /auth/signout"]
RSC["Server Components<br/>(read the signed-in user)"]
end
subgraph Supabase
AUTH["Auth<br/>email + Google"]
PG[("Postgres<br/>profiles · contacts · calls<br/>Row Level Security")]
end
Google["Google OAuth"]
UI -- page requests --> PX
PX --> RSC
SBC -- "queries with the user's JWT" --> PG
SBC --> AUTH
RH --> AUTH
AUTH <--> Google
RSC --> PG
Most reads and writes go directly from the browser to Postgres with the user's session token. There is no custom API layer to secure: the database decides what each request may see.
| Table | Columns |
|---|---|
profiles | id → auth.users, full_name, created_at (created by a trigger on sign-up) |
contacts | id, user_id, company, name, title, stage (contacted | call_scheduled | called), follow_up_date, notes, linkedin_url, is_example, created_at, updated_at |
calls | id, user_id, contact_id → contacts, starts_at, duration_minutes (default 30) |
contact_notes | contact_id → contacts (one per contact), user_id, doc (JSON notes document), updated_at |
contacts also has an optional email. contacts.notes holds a plain-text copy of the notes document so the grid
preview, search, and CSV export never need to load every document.
Every foreign key to auth.users is on delete cascade, so deleting an account removes all of its data. SQL lives in
supabase/migrations.
select / insert / update / delete policies require
auth.uid() = user_id (or = id for profiles). Logged-out requests match no policy. The calls insert/update
policies (and the same policies on contact_notes) also check that the linked contact belongs to the same user, so
you can't attach a call or notes to someone else's contact. (0002_rls.sql)security definer function that can only delete the caller's own
auth.users row. (0003_functions.sql)tests/rls/isolation.test.ts signs in as two ordinary users and
checks that user B can't read, update, delete, or insert into user A's contacts, calls, notes, or profile, and that
logged-out requests see nothing.@supabase/ssr keeps the session in HTTP cookies; proxy.ts validates the JWT (getClaims) on each
request. Server code never trusts an unverified session.?next= values pass through safeNextPath(), which rejects absolute and protocol-relative URLs
(no open redirects). Log out is POST-only.=, +, -, or @ so a malicious name can't run a spreadsheet
formula..env.local is git-ignored; documents every variable.You need Node.js 24+ and a free Supabase project.
git clone https://github.com/tfinn18/coverage.git
cd coverage
npm install
cp .env.example .env.local # add your Supabase URL and publishable key
npm run dev # http://localhost:3000
supabase/migrations/ in order (0001 → 0005).http://localhost:3000/** to Redirect URLs.https://<project-ref>.supabase.co/auth/v1/callback as an authorized redirect URI, and paste the client ID and
secret into Supabase → Authentication → Sign In / Providers → Google.| Command | What it checks |
|---|---|
npm run lint · npm run typecheck | ESLint and TypeScript |
npm test | 60 unit tests: CSV and PDF parsers (with fixture files), import mapping and duplicate detection, sort/filter, follow-up flags, scheduling helpers, Google Calendar links, the notes document (including converting the old layout), list editing, Gmail and mailto links, safe redirects |
npm run test:rls | 8 checks that one user can't touch another's rows, including notes (needs two test accounts in .env.local) |
npm run test:e2e | Playwright: sign in, add a contact, reload, see it on the calendar, delete it; write and reopen notes (Enter/Backspace lists, Copy, Open in Gmail, Escape), notes from the old layout open in the new one; the notes sheet at phone width; plus axe WCAG 2.1 AA scans of 8 pages and the open notes panel in light and dark mode. E2E_BASE_URL=https://coverage-green.vercel.app runs it against production |
GitHub Actions runs lint, typecheck, unit tests, and a production build on every push. The RLS and end-to-end suites need real credentials, so they run locally.
src/
app/ routes: landing, privacy, (auth) pages, (app) pages, auth route handlers
components/ ui primitives, contacts grid, import dialog, calls calendar
lib/ framework-free logic (unit-tested): contacts, csv, pdf, linkedin, import, calls
lib/supabase/ browser client, server client, session proxy
proxy.ts route guard (Next.js 16's name for middleware)
supabase/migrations/ schema, RLS policies, functions
tests/ unit tests, fixtures, RLS isolation test
e2e/ Playwright end-to-end and accessibility tests
A starting point for interviews and resume bullets. Edit it into your own words.
security definer SQL function instead, so no secret key exists in the codebase or on Vercel.CLAUDE.md records the
conventions it followed.Resume bullets (examples):
Supabase's free plan only allows editing the auth email templates once you configure a custom SMTP server, so Coverage uses Supabase's default confirmation and password-reset emails.
Those default emails use the PKCE flow: the link carries a one-time code that can only be exchanged
for a session in the same browser that requested the email (a secret "code verifier" is stored there).
What that means in practice:
How to remove the limitation: add custom SMTP in Supabase (Authentication → Emails → SMTP Settings;
a free tier from a provider like Resend or Brevo works), then change the two templates so their links
use a token_hash, which /auth/confirm already supports on any device:
<!-- Confirm signup -->
<a href="{{ .RedirectTo }}?token_hash={{ .TokenHash }}&type=email">Confirm your email</a>
<!-- Reset password -->
<a href="{{ .RedirectTo }}&token_hash={{ .TokenHash }}&type=recovery">Reset your password</a>
(The reset link uses & because its redirect URL already contains ?next=/reset-password.)
.env.example