Tracecard
Nate James

Nate James

United States

Backend & Infrastructure, Data Integrations, Full-stack Web

Available for work

HTML-to-PDF service

Repo verified

A .NET render service that keeps Chromium behind a Redis queue, so a slow page can't take the API down with it.

FlareCut start screen with a New project button and a recent video

FlareCut

Repo verified

A video editor that runs entirely in the browser. Clips, projects and effects stay on the device, and the editing rules are pure TypeScript with no DOM and no clock, so they test without one.

Syncflow

Repo verified

A visual two-way sync platform. Connects Airtable, Supabase and Postgres and keeps records in step in both directions, with team access enforced by row-level security.

scrixo: sign a PDF free, right in your browser

scrixo

Repo verified

A browser PDF signer. Fill a PDF's existing form fields, sign, and download, with fields still fillable afterward. Files stay in the browser.

Social Fox: let your code do the talking

Social Fox

Repo verified

A social content platform with an AI chat copilot, a drag-and-drop content calendar, thread planning and X analytics. Scheduled posts run on AWS Lambda.

Debriefly trading dashboard with daily P&L, win rate and a performance chart

Debriefly

Repo verified

An AI trading journal. Import trades from a broker or CSV, then review performance, behavior patterns and strategy.

About

I build the backend pieces other things depend on: render services, queues, and integrations that keep data in sync between systems. I care about the failure cases, like what happens when a worker dies mid-job or a third-party API goes slow, and I design so one bad request can't take everything else down.

Works in
.NET, ASP.NET Core, TypeScript, React, Next.js, PostgreSQL, Supabase, Redis, Docker, AWS
Focus
Backend & infrastructure, data integrations, full-stack web
Location
United States
Status
Available for work
Find me
github.com/strawhatx · @heynathanielj
← All work
.NET 10ASP.NET CorePostgreSQLRedisPlaywrightEF CoreDocker

Putting a browser behind a queue so it can't take the API down

An HTML-to-PDF service in .NET. Rendering means running Chromium, which is slow, memory-hungry, and fails in ways an HTTP handler has no good answer for. So rendering doesn't belong in the request: the API takes the job, Redis holds it, and a separate worker does the rendering.

In progress · queue, worker and safety checks built and tested

Nate JamesBackend & Infrastructure, Data Integrations, Full-stack Web

Key decisions

Visibility timeout5 min

A claimed job sits in a Redis processing set. If a worker dies holding it, a sweeper puts it back in the queue, checking every 30 seconds.

Browser contextsCapped

One per CPU core, at least 2. Bursts wait on a semaphore instead of running the host out of memory.

SSRF checks2 per URL

Private and cloud-metadata addresses are blocked before a job is queued and again inside the browser, which closes the redirect and DNS-rebinding gap.

Tests23

API, SSRF rules, and page-break fixtures: nested tables, floats across a break, orphans and widows, table headers with rowspan.

How it's built

BUILTNEXT: API ENQUEUES JOBS

The hard part

A browser is a terrible thing to put in a request path. Chromium takes hundreds of megabytes, a page with a slow web font can hang for the full timeout, and when it dies it takes whatever shares its process with it. Rendering inline means one bad template slows down every other caller.

Moving it to a worker means a job can't be lost when that worker dies. I chose at-least-once delivery: a job that isn't marked done within five minutes goes back in the queue. The tradeoff is that a slow but still-running render can occasionally run twice, which is cheaper than a customer's PDF silently never arriving. The Chromium revision is pinned for the same reason: a renderer that quietly picks up a different browser is a bug you'd only find in production.

Build log

  1. Project skeleton

    Solution split into api, core, data, queue and renderer projects.

  2. Database wiring

    EF Core with separate reader and writer endpoints, and an IAM token in place of a stored password for Aurora.

  3. Queue and renderer

    Redis queue with a processing set and visibility timeout, the Playwright worker, and the browser pool.

  4. Full local stack running

    One script starts Postgres and Redis in Docker, applies migrations, and runs the worker and API.

  5. Diagnostics and tests

    A console harness for running one HTML file through Chromium, plus unit tests for the API and SSRF rules.

  6. Page-break fixture suite

    Real-browser tests for the layouts PDF engines usually get wrong.

  7. Connect the API to the queue

    POST /v1/convert will return a job id right away instead of a placeholder PDF, and callers poll /v1/jobs/{id}.

The API

From the repo
GET/health
200 OK
{ "status": "ok" }

Every route except health requires an API key.

← All work
Next.jsTypeScriptMediaPipeWebGLIndexedDBVitest

A video editor whose editing rules don't need a browser to test

A video editor that runs entirely in the browser, with no server, database or login. You tap a person or object, FlareCut tracks it, and effects follow it through the clip. Footage, projects and your effects library stay on your device.

Working editor · 410 tests

Nate JamesFlareCut · Solo build

Key decisions

Tests410

The editing rules live in pure TypeScript, so they run in plain unit tests without a browser.

Servers0

Projects and the effects library are stored on the device in IndexedDB.

Domain importsNone

The core never touches React, the DOM, canvas, workers, the clock or random. Time and IDs are passed in.

TracingOnce per file

Each video is fingerprinted by its hash, so traced objects are reused and duplicated clips keep their effects.

How it's built

MY CODE (DEPENDENCIES POINT INWARD)SERVICES IT USES

The hard part

Tracking only works if the effect stays attached to the right thing while you edit. Trim a clip, move it, or duplicate it, and an outline drawn at "timeline second 4" now points at the wrong frame.

So masks and tracking are stored by source file and source frame, never by timeline position, and every effect has exactly one target that it follows wherever the target goes. Those rules are written down in the repo and enforced in the domain layer, which is why they can be tested 410 ways without opening a browser. Tracking also cancels out camera motion and flags frames it isn't sure about, so you can fix them on a roto screen.

Build log

  1. Tap-to-track editor

    First version: analyze the video first, then track what you tap.

  2. Timeline and first effects

    Effect clips, impacts, zoom, sound, and body-part targeting. Landing page with a waitlist.

  3. Footage tools

    Split, cutouts and paths. Multiple videos, with cutouts as their own layers.

  4. Roto screen

    Check and fix cutouts frame by frame. Whole-person tracking.

  5. Effect engines

    Frame, text, motion and object engines, particles as data, and projects saved on the device.

  6. Trace once, fixed layer order

    Videos fingerprinted so tracing is reused. Timeline rules written down. Merged to main.

From the commit history: 65 commits, Sep 25 to Sep 30, 2026.

← All work
TypeScriptReactSupabasePostgreSQLAWS LambdaVitest

Keeping records in step between apps that weren't built to talk to each other

A two-way data sync platform. Connect Airtable, Google Sheets, Supabase or a database, map tables and fields, pick a direction, and Syncflow keeps them in step.

Core sync built · 62 tests

Nate JamesSyncflow · Solo build

Key decisions

Sync directions3

Source to destination, the reverse, or two-way, set per table mapping.

Conflict rules3

When both sides changed: source wins, destination wins, or the latest edit wins.

Change checksEvery 5 min

A scheduled Lambda polls for changes, alongside a webhook handler for sources that push.

AccessRow-level

Teams only see their own connections and jobs, enforced in Postgres rather than in app code.

How it's built

MY CODESERVICES IT USES

The hard part

Most of these tools have no change feed. To avoid re-reading whole tables every five minutes, the sync uses each source's own "last modified" field: Airtable's Last Modified Time, Notion's last_edited_time, or an updated_at column. Large tables (10k+ rows) are required to have one, so incremental sync still scales.

Two-way sync means both sides can change the same record. Each table mapping carries its own conflict rule, and field mappings can transform values on the way through. Fetching a source's schema started as an edge function and moved into a database function, so it only runs for a logged-in user and can't be handed arbitrary input.

Build log

  1. Project start

    Flows list and detail pages.

  2. Database and auth

    Tables created, auth context fixed, first integrations.

  3. Provider schema lookup

    Edge function to list a source's databases and tables.

  4. Rate limiting

    Backend rate limits, with docs.

  5. Schema lookup locked down

    Moved to a database function: logged-in callers only, no arbitrary input.

  6. Permissions

    Page guards, metadata sync config, and a job permission fix.

  7. Sync logic done

    Filters split out into their own types next.

  8. Services in TypeScript

    Sync services converted and linked to SQL, then tests.

From the commit history: 112 commits, May 21 to Aug 2, 2025.

← All work
Next.js 15TypeScriptPDF.jspdf-libTailwind

Filling and signing any PDF without breaking its form

A browser PDF signer. Open a PDF, fill its existing fields, place a signature, and download. No account needed, and files stay in the browser for the session.

Live at scrixo.com

Nate Jamesscrixo · Solo build

Key decisions

Field types5

Text, date, signature, checkbox and radio, read from whatever PDF is uploaded.

Field names assumedNone

Import reads the form's own structure instead of expecting known names.

After downloadStill fillable

Values go back into the original fields, so the file works in Preview, Chrome and other readers.

Server for guestsNone

Upload, edit, download. Nothing is saved to a backend.

How it's built

MY CODESERVICES IT USES

The hard part

Real-world PDFs are messy. Signature boxes often never make it into the form's catalog, and field names are whatever the author typed. So import doesn't trust either: it reads the AcroForm catalog, then scans every widget on every page, and classifies each one from its PDF type and flags (/Tx, /Sig, /Btn, radio or checkbox).

Export writes the values back into those same widgets instead of flattening the page, so the downloaded file is still a working form. A drawn signature is embedded as an image over its box. In September I cut the product down to signing only and hid merge, split and rotate from the menu, because one job done well beat six done halfway.

Build log

  1. Editor rebuild

    New editor and header navigation.

  2. Free accounts

    Most of the free path working.

  3. MVP release

    Login removed so guests can sign without an account.

  4. Analytics and SEO

    Analytics, plus pages for common signing searches.

  5. Sign only

    Narrowed the product to signing.

  6. Cleanup

    Removed dead and competing pages, canonical URLs, updated FAQ.

  7. Search analytics

    Ahrefs analytics added.

From the commit history: 77 commits, Dec 31, 2025 to Sep 26, 2026.

← All work
Next.js 14TypeScriptPrismaPostgreSQLStripeAWS LambdaEventBridge

Publishing posts on schedule when nobody has the app open

A social content platform for X. An AI copilot helps you write and refine posts, a drag-and-drop calendar plans them, a thread planner structures longer posts, and analytics show what drove followers and replies.

Full product · 499 commits

Nate JamesSocial Fox · Solo build

Key decisions

SchedulerEventBridge

Scheduled posts are published by a Lambda on a timer, not by the web app.

Plans3 tiers

Usage limits per feature and billing period, tracked in one quota system.

PaymentsStripe

Checkout and webhooks, with webhooks handled on Lambda.

Data models10

Posts, conversations, library and usage in Postgres through Prisma.

How it's built

MY CODESERVICES IT USES

The hard part

A scheduled post has to go out at 9:00 whether or not anyone has the app open, and a Next.js app on Netlify only runs when someone makes a request. So scheduling lives outside the app: posts are saved to Postgres, and an EventBridge timer wakes a Lambda that publishes whatever is due through the X API.

The scheduler took several rounds of fixes in September before it was reliable. Scheduling is refused if the user hasn't connected an account, so a post can't silently fail at 9:00. Every AI action also counts against a per-feature quota for the billing period, so a plan's limits hold no matter which screen the request comes from.

Build log

  1. Project start

    First screens and X OAuth.

  2. Editing and scheduling

    Posts can be edited and scheduled from the content feed.

  3. Safer scheduling

    Scheduling refused when no account is connected.

  4. Payments

    Pricing and Stripe, then webhook fixes for credits.

  5. Scheduler queue working

    First working background scheduler.

  6. AI chat

    First version of the copilot chat.

  7. Library and scheduler

    Interactive content library. v3 merged in October.

  8. Calendar

    Calendar loads editor data, plus bulk post generation.

  9. Analytics

    Analytics dashboard and thread fixes.

From the commit history: 499 commits, Jul 29 to Nov 7, 2025.

← All work
ReactTypeScriptSupabaseAWS LambdaDynamoDBGeminiStripe

Running AI trade reviews inside a free-tier rate limit

An AI trading journal. Import trades from a broker or CSV, see P&L, win rate and history, and get an AI review of your behavior and strategy.

Full product · 328 commits

Nate JamesDebriefly · Solo build

Key decisions

Gemini calls15 / min

A shared limit in DynamoDB holds every Lambda to the free tier together.

WorkerEvery minute

A scheduled Lambda picks up pending analysis jobs.

Edge functions6

Payments, Stripe webhooks, email, forex rates and validation, and stock lookups.

Migrations13

Database schema changes kept in Supabase migrations.

How it's built

MY CODESERVICES IT USES

The hard part

The AI review first ran in a Supabase edge function. That broke twice over: edge functions stop after 60 seconds, and Google tightened the free-tier rate limit. So in June I moved analysis out of the request. Importing trades now creates a job, and a Lambda worker wakes every minute, marks one pending job as processing, and runs it.

With several Lambdas running, each one counting its own calls would blow through the limit. The count lives in DynamoDB instead: a worker can only record a new call with a conditional update that succeeds while fewer than 15 calls sit in the current one-minute window, so the limit holds across all of them. Earlier work went into the parts traders notice first, like imports with missing exit prices and correct P&L.

Build log

  1. Project start

    Navigation, broker sync and trade import.

  2. Import edge cases

    Empty accounts and trades with no exit price handled.

  3. P&L

    Improved P&L calculation and a refactored import.

  4. Payments

    Stripe integrated.

  5. Behavior analysis

    Behavior page, then debriefs built before adding AI.

  6. AI analysis

    Edge function with ChatGPT as the main model and Gemini as fallback.

  7. Strategy

    Behavior chart done, strategy page started.

  8. Background worker

    Rate limits and the 60-second limit led to a Lambda job worker.

  9. Job processing

    Background analysis jobs running.

From the commit history: 328 commits, Feb 11 to Aug 2, 2025.