Release History

Changelog

What's been built, how it was solved, and why it matters — written for developers and clients equally.

LaunchFeatureInfrastructureSecurityFix
v1.3.0LatestSecurity

Security, Credentials & Quality Gates

Every proposal is now screened for abuse. Your certifications are live. The codebase has its first automated test suite.

What shipped

Scam & abuse detection on the proposal form

Hostile submissions — insults, spam, discriminatory content — are silently blocked before any email reaches the inbox. The filter runs three layers: keyword matching, an AI content policy check (OpenAI Moderation API, free endpoint), and an autonomous learning system that extracts new block-terms from flagged content and persists them to cloud storage for future fast-path blocking.

Admin moderation dashboard

A private dashboard at /admin/submissions shows every proposal ever submitted — clean and blocked alike — with detection source, categories flagged, confidence scores, and a submission excerpt. No personal data stored beyond what's needed for observability.

Certified credentials section

Your 10 verified badges from MongoDB, Google Cloud, Certiprof, and others now appear on the homepage, pulled live from the Credly API and cached for 24 hours. Each badge links back to the verified credential on credly.com.

Newsletter security hardening

The subscribe endpoint now validates that the email domain actually accepts mail (DNS MX check), rejects 20+ known disposable/throwaway providers (mailinator, guerrillamail, yopmail…), and enforces a per-IP rate limit of 2 subscriptions per hour — all without a third-party service.

Google OAuth fixed

Root cause: environment variable set with a trailing newline character (%0A), making Google's client lookup fail with invalid_client. Re-added all credentials using printf '%s' to prevent shell newline injection. Both production and sandbox now authenticate correctly.

Proposal flow integration tests

8 automated test cases run against the live API: valid submission, validation errors (short title, invalid email, empty currency, no price), silent moderation block, rate limit enforcement, and malformed JSON. Run with npm run test:proposal:sandbox or npm run test:proposal:prod.

What this means for you as a client

Your inbox is protected by a multi-layer content filter — hostile submissions are silently blocked before any email is sent. Verified credentials from MongoDB, Google Cloud, and Certiprof are now visible to anyone evaluating your profile.

Developer notes▼ expand

Moderation runs three layers: a hardcoded keyword blocklist (seeded from a real abuse case), a custom Vercel Blob blocklist that grows autonomously when OpenAI flags new patterns, and the OpenAI Moderation API as a final layer. The system fails open — if the API is unavailable, legitimate proposals still go through. The newsletter endpoint gained MX record DNS resolution to reject fake domains without any external API dependency.

Skills demonstrated

OpenAI Moderation APIDNS MX validationVercel Blob storageOAuth 2.0 debuggingCredly REST APIIntegration testingRate limiting
v1.2.0Feature

Brand Identity, Themes & Proposal UX

A real visual identity. Seven colour palettes. A proposal form that actually works end-to-end.

What shipped

Circuit tree logo & brand mark

A geometric circuit-tree SVG mark — monochromatic, currentColor, fully theme-adaptive. The icon appears in the header alongside the wordmark and in the footer as the full mark. One SVG responds correctly to every theme and dark/light mode without extra CSS.

Seven visual themes

Forest Node (default for first-time visitors), Circuit Dark, Circuit Light, Terminal Green, Plasma Purple, Titanium Gray, and Aurora. Each palette is a complete design token set — headings, code blocks, gradients, borders, and prose typography all adapt. Returning visitors get a random theme on each session.

Theme picker

A popover component with colour swatches, theme names, and descriptions. The active theme shows a live primary-colour dot on the trigger button. Replaces the plain dark/light toggle with something that expresses the breadth of the visual system.

Multi-step proposal form (5 steps)

Client info → Project details → Budget → Contact → Schedule. Each step validates independently with Zod before advancing. The budget step accepts both hourly and fixed-price inputs in USD and EUR, with a flexibility selector. Error messages are inline and field-level.

Cal.com discovery call scheduler (Step 5)

Embedded Cal.com calendar on the final step with loading skeleton, MutationObserver-based ready detection, and a fallback direct-booking link if the embed times out. The script preloads from step 3 to eliminate cold-start latency.

Web push notifications

Visitors can opt into push notifications for new blog posts. A service worker handles delivery. VAPID key pair configured for both production and sandbox environments.

Newsletter sign-up

Minimalist inline and banner variants on the blog index and per-article header. Subscribers stored in Vercel Blob with deduplication.

Prose readability on dark themes

Custom --tw-prose-* CSS variable overrides for every dark palette class, so article text, headings, links, and code blocks are readable regardless of which theme is active — not just the built-in .dark class that Tailwind Typography assumes.

What this means for you as a client

The site now has a distinctive brand that looks intentional across every device and theme. Potential clients can submit a detailed project proposal and book a discovery call — all in a single guided flow without leaving the page.

Developer notes▼ expand

The palette system uses CSS custom property blocks per theme class on <html>. Each palette defines 12 semantic tokens (background, foreground, primary, accent, gradient-from/to, etc.) — no Tailwind class changes needed when switching themes. The Cal.com embed has a MutationObserver-based ready detection (no native callback exists) with a 10s timeout fallback to a direct booking link. The preloader starts injecting the Cal script at step 3 so it's warm by step 5.

Skills demonstrated

Design systemsCSS custom propertiesNext.js App RouterCal.com embed APIMulti-step form patternsWeb Push APICloudinary CDNSVG icon systems
v1.1.0Infrastructure

YouTube Pipeline & DevOps Infrastructure

Blog posts can now become YouTube videos in one click. The codebase got branch protection, CI/CD, and conventional versioning — in 23 minutes.

What shipped

AI-powered blog-to-YouTube pipeline

Every blog post gets a "Publish to YouTube" button visible only to the admin. The pipeline:

  1. GPT-4o reads the post and writes a structured video script
  2. OpenAI TTS (onyx voice) narrates each section
  3. Shotstack composes the audio with animated slide visuals
  4. The finished video uploads directly to the YouTube channel via the Data API v3

All processing is server-side. The UI shows live progress with per-step status indicators.

Google OAuth with automatic token refresh

Admin authentication via Google OAuth 2.0. Access tokens (1-hour lifespan) are automatically refreshed using the stored refresh_token — no re-authentication required mid-session.

Branch protection & CI/CD (23 minutes)

Established via the GitHub REST API in a single directed session:

  • main branch requires PR + 3 passing CI checks + linear history + no force push
  • GitHub Actions CI: TypeScript type-check, ESLint, and Next.js build on every PR
  • GitHub Actions release: standard-version auto-bumps version + generates CHANGELOG on every merge to main
  • Conventional Commits enforced via commitlint + Husky pre-commit hook

Sandbox environment

A sandbox branch deploys automatically to sandbox.js17.dev on Vercel — a complete staging environment with its own env vars, domain, and deployment pipeline. All new features ship to sandbox first.

Security hardening

  • YouTube upload moved server-side (eliminated CORS vulnerability)
  • Proxy video route restricted to Shotstack CDN hostnames only (SSRF mitigation)
  • MDX CVE patch: upgraded next-mdx-remote to v6 (CVE-2026-0969)

What this means for you as a client

A single 'Publish to YouTube' button on any blog post triggers a full AI-powered video production pipeline: GPT-4o writes a script, OpenAI TTS narrates it in a professional voice, Shotstack renders slides with motion graphics, and the result uploads directly to YouTube. The entire DevOps foundation took 23 minutes to establish — the kind of velocity available when working with AI-augmented engineering.

Developer notes▼ expand

The YouTube upload is server-side via a Next.js API route — a critical fix from the original client-side approach which hit CORS blocks. The Shotstack job is polled via a /video-status/[jobId] route until complete. OAuth token refresh is handled in the NextAuth JWT callback: refresh_token stored on initial sign-in, auto-refreshed when accessTokenExpires is past. The SSRF vulnerability in the proxy-video route is mitigated by a Shotstack CDN hostname allowlist.

Skills demonstrated

YouTube Data API v3OpenAI GPT-4o + TTSShotstack video renderingGitHub Actions CI/CDBranch protection strategyOAuth 2.0 token refreshVercel Blob storageServer-side media pipeline
v1.0.0Launch

Platform Launch

js17.dev goes live — a full-stack personal command centre built with Next.js 14, AI-augmented from day one.

What shipped

Full-stack Next.js 14 site

Built on the App Router with a clear separation between server components (data fetching, OG images, GitHub stats), client components (animations, forms, theme), and edge functions (OG image rendering). TypeScript throughout — no any.

MDX blog engine

Author posts in Markdown + JSX. Frontmatter drives metadata, OG images, and the post list. Syntax highlighting via rehype-pretty-code. Reading time calculated automatically. Posts live in src/content/blog/ as .mdx files — no CMS, no database, no subscription.

Live GitHub activity

Contribution graph and repository stats fetched server-side from the GitHub API with a 1-hour ISR cache. Displays real commit history, language breakdown, and streak data — auto-updating without any manual maintenance.

Multi-step proposal form

A guided 5-step contact flow with per-step Zod validation, email delivery via Resend, and a confirmation email to the sender. Covers client info, project scope, budget expectations, contact preferences, and optional discovery call scheduling.

Dynamic OG images

Every page and every blog post generates a branded Open Graph image at request time using the Edge runtime — no image editing, no static files to maintain. Correct previews on Twitter, LinkedIn, Slack, and iMessage automatically.

Transactional email

Proposal submissions trigger two emails: a structured HTML brief to the inbox (with client info, project details, budget, contact, and notes) and a professional confirmation to the client with next steps. Powered by Resend with lazy initialization.

Performance & SEO baseline

  • Lighthouse score: 95+ across all pages
  • robots.txt and sitemap.xml generated at build time
  • Semantic HTML throughout
  • All images with explicit width/height to prevent CLS
  • Inter + JetBrains Mono loaded via next/font (zero layout shift)

What this means for you as a client

A production-grade personal site built to the same standards as client projects: typed end-to-end, server-rendered where it matters, static where it's fast, with email infrastructure, dynamic OG images, and a multi-step contact flow. Every component here is a real-world example of the quality you get when you hire this engineer.

Developer notes▼ expand

The MDX pipeline uses next-mdx-remote for dynamic compilation with gray-matter for frontmatter. GitHub stats use ISR with a 1-hour revalidation window against the GitHub REST API. Resend is lazily initialized at handler time (not module level) to avoid build-time errors when RESEND_API_KEY is absent. All OG images are Edge-runtime-rendered dynamically — no static PNG needed.

Skills demonstrated

Next.js 14 App RouterTypeScriptTailwind CSSMDX blog engineGitHub API integrationResend transactional emailZod validationFramer MotionEdge runtime

Want to see what gets built next? Follow along or start a project.