Rebuilding JSeeQ on the 2026 stack

JSeeQ was a 2022 idea that didn't ship. Here's how it got rebuilt in a weekend's worth of slices on the 2026 Defensible Logic stack.

JSeeQ first existed in 2022, as a Wagtail-and-Django-4 skeleton with an ORM model for opportunities and resumes, a Defensible-Logic black_white theme, and an October one-pager promising a December prototype. None of the prototype shipped. The repo went quiet for three and a half years.

This week it came back. Not by upgrading the 2022 codebase — Django 4 to 6 and Wagtail 3 to 7 across that gap is more painful than starting clean — but by archiving the old skeleton to legacy/ and rebuilding from the one-pager, on the same Phase 0 scaffold defensiblelogic.com and mloduchowski.com share.

What got built

Eight Django apps stacked end-to-end, each shipped as its own small slice with a model, a view or two, a template, and tests:

Pipe — the candidate-side CRM. Employer, Opportunity with a stage enum and follow-up date, Person contacts, an activity log that auto-records stage changes alongside manual notes. Filter and search on the opportunity list. CSV export.

Docs — the resume templater. Master Resume with Sections and Items; tag any item; create Variants that filter by tag. Render to ATS-friendly PDF (single-column WeasyPrint output) or plain text (UPPERCASE section headers, em-dash separator, hyphen bullets — the conventions resume parsers expect).

Billing — Stripe Checkout and Customer Portal, signature-verified webhooks updating per-Candidate plan + subscription state. Free tier caps at 1 resume / 50 opportunities / 5 contacts; Premium and Business unlimited. 14-day trial on first upgrade.

Accounts — signup with email verification, password reset, workspace invites with single-use tokens, role-based permissions (Owner / Coach edit; Advisor / Recruiter comment; Viewer read-only), 2FA via TOTP plus 10 static recovery codes, self-serve account deletion + GDPR data export, email change with old-address notification.

Monitoring — in-house error capture instead of Sentry, in-house rate limiting, both browseable through Django admin. Daily digest emails for new errors and per-user follow-ups.

How it got built

One slice at a time. A slice is roughly: pick the next concrete piece, write the model, the view, the template, the tests; commit; move on. The git log reads as a chain of small commits because that's literally how it landed.

Examples in chronological order: Phase 0 scaffold → CMS content seeded from the one-pager → Pipe MVP → comment thread + follow-up dates → Person contacts → filter + search → Docs slice 1 (master resume) → Docs slice 2 (tags + variants) → PDF export → email backend + mobile CSS + candidate switcher → role permissions → invite flow → daily digest → Stripe billing → email verification → privacy + ToS + in-house monitoring → account deletion + export → rate limiting → 2FA → email change + 2FA recovery → pipe QoL → onboarding.

Each landed in its own commit. Each shipped tests. The code stays small enough to read because nobody designed for hypothetical future requirements — only the next slice.

What's next

The big remaining one-pager promise is integration with Google Docs, Microsoft Office, and LinkedIn — three OAuth surfaces, three API integrations. Smaller, sooner: a refer-a-colleague viral mechanic (the Free tier already mentions points), Stripe coupons and yearly billing, drag-to-reorder on the resume editor.

If you're a candidate — full-time, post-layoff, between roles — try it. The Free tier is enough to run a real job search.

Return to blog