Removing bank data from the source for security reasons#73
Conversation
Agent-Logs-Url: https://github.com/hutoczky/FormatX/sessions/b362c7eb-fcc6-41ff-91bd-9f6da80d0198 Co-authored-by: hutoczky <5453461+hutoczky@users.noreply.github.com>
Agent-Logs-Url: https://github.com/hutoczky/FormatX/sessions/b362c7eb-fcc6-41ff-91bd-9f6da80d0198 Co-authored-by: hutoczky <5453461+hutoczky@users.noreply.github.com>
Agent-Logs-Url: https://github.com/hutoczky/FormatX/sessions/b362c7eb-fcc6-41ff-91bd-9f6da80d0198 Co-authored-by: hutoczky <5453461+hutoczky@users.noreply.github.com>
Agent-Logs-Url: https://github.com/hutoczky/FormatX/sessions/b362c7eb-fcc6-41ff-91bd-9f6da80d0198 Co-authored-by: hutoczky <5453461+hutoczky@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds a hosted checkout/subscription flow for “FormatX Suite Pro” that keeps payment details off the static GitHub Pages site by moving session creation, webhook processing, and license activation to a Cloudflare Worker backed by Supabase.
Changes:
- Adds new billing UI pages (support/terms/privacy + payment success/cancel) and a checkout form + JS that calls a billing API.
- Introduces a new
billing-workerCloudflare Worker implementing Stripe checkout session creation, webhook handling, session status, and license verification, plus Supabase schema and local dev configuration. - Updates repo env examples and gitignore entries to avoid committing billing secrets/config.
Reviewed changes
Copilot reviewed 22 out of 30 changed files in this pull request and generated 12 comments.
Show a summary per file
| File | Description |
|---|---|
| FormatX.sln | Solution configuration tweaks (adds Any CPU configs). |
| docs/scifi-ui/index.html | Adds billing API base meta, rewrites pricing CTA to use a form-based checkout flow, and loads billing.js. |
| docs/scifi-ui/scripts/billing.js | Implements client-side checkout session creation and redirect to hosted checkout. |
| docs/scifi-ui/payment/success.html | New success page that polls the worker for session/license status. |
| docs/scifi-ui/payment/cancel.html | New cancel page for aborted payments. |
| docs/scifi-ui/support.html | New support/enterprise info page. |
| docs/scifi-ui/terms.html | New terms placeholder page (ÁSZF). |
| docs/scifi-ui/privacy.html | New privacy placeholder page. |
| billing-worker/src/index.js | Main Worker implementation: plan catalog, Stripe integration, Supabase persistence, webhook + license logic. |
| billing-worker/supabase-schema.sql | New SQL schema for companies/subscriptions/licenses/events/activations. |
| billing-worker/test/index.spec.js | Adds minimal Vitest coverage (health + 404). |
| billing-worker/vitest.config.js | Configures Cloudflare Workers Vitest pool. |
| billing-worker/wrangler.jsonc | Wrangler configuration (compat date, vars, node compat, observability). |
| billing-worker/package.json | Worker package scripts and dev deps. |
| billing-worker/package-lock.json | Locks worker dependencies. |
| billing-worker/README.md | Worker endpoints + local dev notes. |
| billing-worker/.dev.vars.example | Example local env vars for Stripe/Supabase/license config. |
| billing-worker/.gitignore | Worker-local ignores (vars, wrangler state, node_modules, etc.). |
| billing-worker/.prettierrc | Worker-local Prettier formatting rules. |
| billing-worker/.editorconfig | Worker-local editor config. |
| billing-worker/.vscode/settings.json | VS Code association for JSONC. |
| billing-worker/AGENTS.md | Internal guidance for Cloudflare Workers-related work. |
| .gitignore | Ignores env files and worker local state artifacts. |
| .env.example | Root example env file for billing-related configuration. |
Files not reviewed (1)
- billing-worker/package-lock.json: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const existing = await supabase.selectSingle('payment_events', { | ||
| provider_event_id: ['eq', event.id], | ||
| }); | ||
| if (existing) { | ||
| return jsonResponse({ ok: true, duplicate: true }, 200, corsHeaders); | ||
| } | ||
|
|
||
| await supabase.insert('payment_events', { | ||
| provider_event_id: event.id, |
| company_name: subscription.metadata?.company_name ?? '', | ||
| contact_email: subscription.metadata?.contact_email ?? '', |
| async function handleCreateCheckoutSession(request, env, supabase, provider, corsHeaders) { | ||
| const payload = await request.json(); | ||
| const validationError = validateCheckoutRequest(payload); | ||
| if (validationError) { | ||
| return jsonResponse({ error: validationError }, 400, corsHeaders); | ||
| } |
| function buildCorsHeaders(request, env) { | ||
| const requestOrigin = request.headers.get('Origin'); | ||
| const allowedOrigin = env.FRONTEND_URL || ''; | ||
| const origin = requestOrigin && allowedOrigin && requestOrigin === allowedOrigin ? requestOrigin : (allowedOrigin || '*'); | ||
| return { | ||
| 'Access-Control-Allow-Origin': origin, | ||
| 'Access-Control-Allow-Methods': 'GET,POST,OPTIONS', | ||
| 'Access-Control-Allow-Headers': 'Content-Type,Stripe-Signature,X-Admin-Debug-Token', | ||
| 'Access-Control-Max-Age': '86400', | ||
| }; |
| @@ -0,0 +1,20 @@ | |||
| import { env, createExecutionContext, waitOnExecutionContext, SELF } from "cloudflare:test"; | |||
| import { describe, it, expect } from "vitest"; | |||
| import worker from "../src"; | |||
| } | ||
|
|
||
| async function handleLicenseVerify(request, supabase, corsHeaders) { | ||
| const payload = await request.json(); |
| const result = await response.json(); | ||
| if (!response.ok) { | ||
| throw new Error(result.error || 'Nem sikerült létrehozni a checkout sessiont.'); | ||
| } | ||
|
|
||
| if (!result.checkout_url) { | ||
| throw new Error('A checkout URL hiányzik a válaszból.'); | ||
| } |
| if (request.method === 'GET' && url.pathname === '/api/health') { | ||
| return jsonResponse({ ok: true, provider: env.PAYMENT_PROVIDER ?? 'stripe', mode: env.PAYMENT_MODE ?? 'test' }, 200, corsHeaders); | ||
| } | ||
|
|
||
| if (request.method === 'POST' && url.pathname === '/api/create-checkout-session') { | ||
| return await handleCreateCheckoutSession(request, env, supabase, provider, corsHeaders); | ||
| } | ||
|
|
||
| if (request.method === 'POST' && url.pathname === '/api/webhook') { | ||
| return await handleWebhook(request, env, supabase, provider, corsHeaders); | ||
| } | ||
|
|
||
| if (request.method === 'GET' && url.pathname === '/api/session-status') { | ||
| return await handleSessionStatus(url, supabase, corsHeaders); | ||
| } | ||
|
|
||
| if (request.method === 'POST' && url.pathname === '/api/license/verify') { | ||
| return await handleLicenseVerify(request, supabase, corsHeaders); |
| <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> | ||
| <link href="https://fonts.googleapis.com/css2?family=Rajdhani:wght@600;700&family=Orbitron:wght@700;900&family=Share+Tech+Mono&display=swap" rel="stylesheet"> | ||
| <meta name="theme-color" content="#0a0c0f"> | ||
| <meta name="formatx-billing-api-base" content="/api"> |
| <meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover"> | ||
| <meta name="formatx-billing-api-base" content="/api"> | ||
| <title>Fizetés sikeres — FormatX Suite Pro</title> |
|
FONTOS KIEGÉSZÍTÉS: A Revolut integráció ne frontend-only legyen. A GitHub Pages csak statikus frontend. Használható backend:
Frontend:
Backend:
Tilos:
A licenc csak akkor aktiválódjon, ha a Revolut webhook vagy hiteles fizetési állapot szerint a fizetés completed / paid. Környezeti változók: REVOLUT_MODE=sandbox vagy live Legyen külön sandbox és live mód. Sandbox: Live: Acceptance criteria:
|
Pull request created by AI Agent