00

Web · 2026

Logic & Code

Year
2026 – now
Scope
Web · Personal
Role
Full-stack Engineer
Team
Solo
Stack
Next.js, React, TypeScript, Tailwind CSS
Status
Ongoing

A try-out platform at gerbangdev.com for people preparing for the Apple Developer Academy @BINUS selection.

An independent web platform, not an official Apple product, where candidates read up on the Apple Developer Academy @BINUS selection, practise logic and code questions under a server-authoritative timer, and prepare their CV and portfolio. Freemium: practice runs on a rolling token balance, the AI-assisted document builder sits behind payment.

The product follows one arc: understand the selection, practise and measure yourself, then prepare the documents. Three surfaces carry it: admin-editable info pages, a scored try-out engine, and a CV and portfolio builder where an AI pass tidies the writing and a PDF comes out the other end.

Read moreShow less

Everything that decides an outcome lives on the server. The client never selects from the questions or options tables at all; a question reaches the browser through a SECURITY DEFINER RPC that strips the answer key, and scoring happens in the database. The deadline of an attempt is written by the server when the attempt starts, so a tampered clock changes nothing, and a background function closes attempts that ran past it.

The same rule holds for money. Tokens only ever increase through an HMAC-SHA256-signed webhook; the browser redirect after payment credits nothing. Prices and token counts are mapped server-side from a pack id, so the browser sends an id and never an amount. A user's role and account status are immutable from the client, enforced by a database trigger rather than by a form that hides the field.

The token economy runs without a scheduler. A signup starts at 50 tokens and tops back up to 50 every 72 hours, computed lazily when the balance is read or an attempt starts, and a top-up never lowers a balance, so purchased tokens above 50 are safe. Starting an attempt costs the package's token price; resuming one is free.

Schema changes are file-based across 20 migrations, never made through the Supabase dashboard, so development and production do not drift apart. The quality gate is a single command covering typecheck, lint, unit tests, and a scan for secrets leaking into the client bundle.

Logic & Code portfolio cover showing its measured learning system, Logic Core module, 45-minute timer, and server-verified scoring
Logic & Code user flow from landing page and authentication through package selection, timed questions, server scoring, and result review

01 / 02

An independent try-out platform at gerbangdev.com: structured material, a server-set timer, and scoring the browser cannot reach.

Impact

  • 20

    File-based migrations

    No schema change is made through the Supabase dashboard, so development and production do not drift

  • 4

    Edge functions

    AI refinement, payment creation, signed payment webhook, and PDF generation

  • 9 + 6 + 5

    Test suites

    Nine Vitest unit files, six Playwright end-to-end suites, and five pgTAP database suites

  • 50 / 100 / 500

    Token packs

    Priced at Rp10,000, Rp20,000, and Rp80,000

  • 72h

    Free token refresh

    Balance rolls back up to 50, computed lazily with no scheduled job

Brief

Problem

Candidates preparing for the Apple Developer Academy @BINUS selection have no measured way to practise the logic and code section, and the information about the process itself is scattered. A practice platform that scores in the browser is worthless the moment someone opens developer tools: the answer key, the timer, and the balance all have to be out of reach.

Solution

Put every decision on the server: questions served through a SECURITY DEFINER RPC without the answer key, scoring inside the database, deadlines written by the server, and tokens credited only by a signature-verified webhook. On top of that sits a freemium loop; a rolling token balance for practice, payment for the AI document builder.

My role

  1. 01

    Built the whole platform solo: Next.js App Router frontend, Postgres schema, RPCs, and Deno edge functions

  2. 02

    Designed the security boundary so the answer key, the attempt deadline, prices, and token balances are all server-owned and unreachable from the client

  3. 03

    Wrote the token economy as a lazy 72-hour rolling top-up that needs no cron job and never lowers a purchased balance

  4. 04

    Integrated SayaBayar as a hosted invoice flow with HMAC-SHA256 webhook verification and an idempotent settlement function

  5. 05

    Built the admin side: users, packages and questions, editable info content, results, payments, templates, traffic, and settings

  6. 06

    Kept schema changes to 20 file-based migrations so development and production never drift

  7. 07

    Set up the quality gate: Vitest units, Playwright end-to-end suites, pgTAP database tests, and a scan for secrets reaching the client bundle

Features

  1. 01

    Admin-editable selection info pages served from the database at /info/[slug]

  2. 02

    Logic and code try-outs with autosaved answers, a server-set deadline, and automatic scoring

  3. 03

    Questions delivered without their answer key: the client never reads the questions or options tables

  4. 04

    One ongoing attempt per user per package, held by a partial unique index

  5. 05

    Rolling token balance: 50 at signup, topped back up to 50 every 72 hours, computed without a scheduler

  6. 06

    Token packs of 50, 100, and 500 at Rp10,000, Rp20,000, and Rp80,000

  7. 07

    CV and portfolio builder with an AI pass that tidies wording without adding content, and a private PDF export

  8. 08

    Admin panel covering users, packages, questions, content, results, payments, templates, traffic, and settings

  9. 09

    Built-in traffic analytics: page views and login events with admin summaries

  10. 10

    Environment-driven feature flags that gate premium, signup, AI refinement, and PDF generation as UX valves rather than security boundaries

Architecture

A Next.js App Router frontend split into four route groups (the signed-in app, auth, admin, and public pages) against a Supabase backend where the security actually lives. Reads and writes that matter go through SECURITY DEFINER RPCs rather than table access: starting an attempt, fetching its questions, autosaving an answer, submitting and scoring, refreshing the token balance, creating and settling a payment. Row-level security covers the rest, with admin authorisation and an audit trail as their own functions. Four Deno edge functions hold everything that needs a secret or an external call: the AI proxy, payment creation, the signed payment webhook, and PDF generation into a private bucket. Code is organised by feature rather than by layer, and schema lives in 20 ordered migrations deployed by GitHub Actions alongside the Vercel frontend.

Front end
Next.js, React, TypeScript, Tailwind CSS, TanStack Query, React Hook Form, Zod
Back end
Supabase Edge Functions, Deno, PL/pgSQL
Data
PostgreSQL, Supabase Auth, Supabase Storage
Infrastructure
Vercel, Supabase, GitHub Actions
Tools
ESLint, Prettier, Husky, lint-staged, Vitest, Playwright, pgTAP
Integrations
SayaBayar, Google OAuth, Supabase

Challenges

  1. 01

    Problem

    A practice platform is worthless if the answer key is reachable from the browser, and row-level security alone still means the client holds a handle on the options table.

    Solution

    The client never selects from questions or options at all. A SECURITY DEFINER RPC assembles the questions for an attempt with the correctness flag stripped, and scoring runs in a database function, so the key never leaves the server.

  2. 02

    Problem

    A timer that lives in the browser can be paused, rewound, or reloaded away, and a scored try-out has to mean something.

    Solution

    The deadline is written by the server when an attempt starts, the browser only renders a countdown against it, and a separate function closes attempts that ran past their deadline.

  3. 03

    Problem

    Crediting tokens on the post-payment redirect is the easiest way to hand out free tokens; anyone can visit a success URL, and a gateway will happily retry a webhook.

    Solution

    The webhook verifies its HMAC-SHA256 signature before doing anything else, finds the row by gateway reference, and calls a service-role-only settlement function that is idempotent, so a replay is a no-op. The redirect credits nothing.

  4. 04

    Problem

    If the browser sends an amount, the browser decides the price; if it can write its own profile row, it decides its own role and premium status.

    Solution

    Prices and token counts are mapped server-side from a pack id, so the browser only ever sends an id. Role and account status are held immutable for the client by a database trigger, not by hiding a field in a form.

  5. 05

    Problem

    A rolling free-token grant usually means a scheduled job, and a naive top-up would wipe out tokens a user had actually paid for.

    Solution

    The top-up is computed lazily whenever the balance is read or an attempt starts, so no cron is needed, and it only ever raises a balance toward 50; a purchased balance above that is left alone.

  6. 06

    Problem

    An AI writing pass on a CV can quietly invent experience the candidate never had, and the model key has to live somewhere.

    Solution

    The key lives only inside an edge function, which authenticates the caller, gates on premium, caps the payload, and passes the result through a guard that permits tidying but not added content.

Lessons

  1. 01

    Anything that decides an outcome (the answer key, the deadline, the price, the balance) has to be owned by the server, not hidden by the client.

  2. 02

    Feature flags are a UX and capacity valve, never a security boundary; the boundary has to hold with every flag switched on.

  3. 03

    A lazy computation at read time replaced a scheduled job entirely, and removed a whole class of drift between what a cron ran and what a user sees.

  4. 04

    Idempotency is cheaper to design in than to retrofit; a payment gateway will replay a webhook, and the settlement path has to treat that as normal.