diff --git a/.gitignore b/.gitignore index 370aa7a..05b5e51 100644 --- a/.gitignore +++ b/.gitignore @@ -32,4 +32,13 @@ FIXES_APPLIED.md .agents/ skills-lock.json graphify-out/ -.superpowers/ \ No newline at end of file +.superpowers/ +docs/roadmap/ +docs/plans/ +docs/specs/ +docs/plan/ +.commandcode/ +test/ +.vercel +.env +.env.local diff --git a/.kilo/agent-manager.json b/.kilo/agent-manager.json new file mode 100644 index 0000000..93d494d --- /dev/null +++ b/.kilo/agent-manager.json @@ -0,0 +1,9 @@ +{ + "worktrees": {}, + "sessions": {}, + "tabOrder": { + "local": [ + "pending:1" + ] + } +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index fae8e3d..2c76624 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,5 @@ { "typescript.tsdk": "node_modules/typescript/lib", - "typescript.enablePromptUseWorkspaceTsdk": true + "typescript.enablePromptUseWorkspaceTsdk": true, + "makefile.configureOnOpen": true } diff --git a/.vscodeignore b/.vscodeignore index 7c1744a..5f681fb 100644 --- a/.vscodeignore +++ b/.vscodeignore @@ -59,6 +59,7 @@ venv/** .cursor/ .nightly/ .kiro/ +.kilo/ .c8rc.phase-handlers.json .c8rc.phase-utils.json .c8rc.phase-report.json @@ -69,4 +70,6 @@ FIXES_APPLIED.md review-the-current-codebase-shimmering-bee.md .github/ .coverage/ -.coverage-unit/ \ No newline at end of file +.coverage-unit/ +packages/ +graphify-out/ \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c9ab5b..82976a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,48 @@ All notable changes to the PostgreSQL Explorer extension will be documented in t The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.2.9] - 2026-05-23 +> Nightly releases - v1.3.11 + +### Added + +- **Parameter comment completions** — Typing `--` in a SQL cell with `$1`/`:name` params now suggests missing `-- $1=` / `-- :name=` definitions. A Quick Fix action inserts all missing stubs at once. + - Example: + ```sql + SELECT * FROM users WHERE id = $1 AND status = :status + ``` + triggers suggestions for: + ```sql + -- $1= + -- :status= + ``` +- **Production safety banner** — Connection form shows a warning banner when environment is Production, prompting you to enable read-only mode. + - **Environment tagging** is now clearer and more reliable, with badges on connection cards and a status bar indicator for active Production connections. + - **Query safety analyzer** now applies a Production risk multiplier to better catch dangerous queries and require confirmation. + - **Status bar risk indicator** now shows a warning icon whenever a Production connection is active. + +### Changed + +- SSL connections tagged as Production no longer silently downgrade to plaintext. +- Explain Analyzer, Schema Designer, AI Assistant, and Saved Queries now route through Pro feature gates with freemium counters. +- Freemium model is 100% functional with clear upgrade paths, and Pro features are fully unlocked in development builds (coming soon). + +--- + +## [1.2.7] - 2026-05-13 +> Nightly releases - v1.3.9 • v1.3.10 + +### Added + +- **Role Designer** — Added a new visual role-management editor from the role context menu, with live SQL preview, notebook handoff, and membership controls for Inherit / Admin Option grants. +- **Notebook parameter bank** — SQL parameter prompts now remember values per notebook, offer quick-pick reuse, and let you clear saved values without affecting other notebooks. +- **Streaming row counts** — Sliding-window result rendering now shows the total row count when it is available, so streamed results read as `start–end of total` instead of only a range. + +### Changed + +- **SQL completion catalog** — Column completion warm-cache queries now read from PostgreSQL catalogs directly, which improves coverage for views and materialized views. +- **Result cursor metadata** — Cursor window messages now carry optional total-row metadata through the renderer path. + ## [1.2.5] - 2026-05-07 > Nightly releases - v1.3.6 • v1.3.7 diff --git a/api/config.js b/api/config.js new file mode 100644 index 0000000..2f3c71c --- /dev/null +++ b/api/config.js @@ -0,0 +1,8 @@ +module.exports = async (req, res) => { + if (req.method !== 'GET') { + return res.status(405).json({ error: 'Method Not Allowed' }); + } + return res.status(200).json({ + key_id: process.env.RAZORPAY_KEY_ID + }); +}; diff --git a/api/create-order.js b/api/create-order.js new file mode 100644 index 0000000..6112b60 --- /dev/null +++ b/api/create-order.js @@ -0,0 +1,63 @@ +const Razorpay = require('razorpay'); + +module.exports = async (req, res) => { + if (req.method !== 'POST') { + return res.status(405).json({ error: 'Method Not Allowed' }); + } + + const { amount, currency, receipt } = req.body || {}; + + // Validate amount + if (!amount || isNaN(amount)) { + return res.status(400).json({ error: 'Amount is required and must be a number' }); + } + + const amountPaise = parseInt(amount, 10); + if (amountPaise < 100) { + return res.status(400).json({ error: 'Amount must be at least 100 paise' }); + } + + if (!currency) { + return res.status(400).json({ error: 'Currency is required' }); + } + + // Initialize Razorpay client + const key_id = process.env.RAZORPAY_KEY_ID; + const key_secret = process.env.RAZORPAY_KEY_SECRET; + + if (!key_id || !key_secret) { + console.error('Razorpay credentials missing from environment.'); + return res.status(500).json({ error: 'Internal Server Error: Razorpay credentials missing' }); + } + + const razorpay = new Razorpay({ + key_id: key_id, + key_secret: key_secret, + }); + + try { + const options = { + amount: amountPaise, + currency: currency, + receipt: receipt || `receipt_${Date.now()}` + }; + + const order = await razorpay.orders.create(options); + + return res.status(200).json({ + order_id: order.id, + amount: order.amount, + currency: order.currency + }); + } catch (error) { + console.error('Razorpay API error:', error); + + // Handle authentication failures (Razorpay SDK might throw or return standard error response) + const errorDescription = error.description || (error.error && error.error.description) || ''; + if (error.statusCode === 401 || errorDescription.includes('Key') || errorDescription.includes('signature')) { + return res.status(401).json({ error: 'Authentication failed with Razorpay API' }); + } + + return res.status(500).json({ error: error.message || 'Failed to create order with Razorpay API' }); + } +}; diff --git a/api/package.json b/api/package.json new file mode 100644 index 0000000..f052526 --- /dev/null +++ b/api/package.json @@ -0,0 +1,6 @@ +{ + "private": true, + "dependencies": { + "razorpay": "^2.9.0" + } +} diff --git a/api/verify-payment.js b/api/verify-payment.js new file mode 100644 index 0000000..46f3399 --- /dev/null +++ b/api/verify-payment.js @@ -0,0 +1,44 @@ +const crypto = require('crypto'); + +module.exports = async (req, res) => { + if (req.method !== 'POST') { + return res.status(405).json({ error: 'Method Not Allowed' }); + } + + const { razorpay_order_id, razorpay_payment_id, razorpay_signature } = req.body || {}; + + // Error handling: Missing fields + if (!razorpay_order_id || !razorpay_payment_id || !razorpay_signature) { + return res.status(400).json({ error: 'Missing required signature verification fields' }); + } + + const secret = process.env.RAZORPAY_KEY_SECRET; + if (!secret) { + console.error('Razorpay Key Secret is missing from environment.'); + return res.status(500).json({ error: 'Internal Server Error: Razorpay Key Secret is missing' }); + } + + try { + // Generate signature using HMAC-SHA256 + const hmac = crypto.createHmac('sha256', secret); + hmac.update(`${razorpay_order_id}|${razorpay_payment_id}`); + const generated_signature = hmac.digest('hex'); + + // Secure timing-safe or straight comparison of generated signature and razorpay_signature + if (generated_signature === razorpay_signature) { + return res.status(200).json({ + success: true, + message: 'Payment signature verified successfully.' + }); + } else { + // Signature mismatch: return 400, do NOT mark as paid + return res.status(400).json({ + success: false, + error: 'Signature verification failed. Potential tampering detected.' + }); + } + } catch (error) { + console.error('Error verifying payment signature:', error); + return res.status(500).json({ error: error.message || 'Internal Server Error during verification' }); + } +}; diff --git a/docs/CNAME b/docs/CNAME index 8123bf2..9f19e7b 100644 --- a/docs/CNAME +++ b/docs/CNAME @@ -1 +1 @@ -pgstudio.astrx.dev +# This file is no longer needed. Custom domain is managed via Vercel Dashboard. diff --git a/src/commands/REFACTORING_GUIDE.md b/docs/REFACTORING_GUIDE.md similarity index 100% rename from src/commands/REFACTORING_GUIDE.md rename to docs/REFACTORING_GUIDE.md diff --git a/docs/WEBSITE_CONTEXT.md b/docs/WEBSITE_CONTEXT.md index d38e10d..bbe8d5f 100644 --- a/docs/WEBSITE_CONTEXT.md +++ b/docs/WEBSITE_CONTEXT.md @@ -1,16 +1,18 @@ # Docs Website Context -Last updated: 2026-04-19 +Last updated: 2026-05-22 Primary entry: docs/index.html +Hosting: Vercel (migrated from GitHub Pages) ## What This Website Is -This site is a product demo and marketing landing page for PgStudio, styled and behaved like a mini VS Code workbench. +This site is a product demo and marketing landing page for PgStudio, styled and behaved like a mini VS Code workbench. It also includes a Razorpay payment checkout for sponsorship/pro support. The core concept is: - Show value by simulation, not by static brochure copy. - Let users interact with a realistic "editor + explorer + SQL assistant" shell. - Keep installation CTA visible from both full and minimized states. +- Enable paid sponsorship via Razorpay checkout (requires server-side API). ## Visual and UX Concept @@ -97,6 +99,23 @@ Primary conversion links: - GitHub repository - Open VSX listing +## Deployment (Vercel) + +The site is deployed on Vercel with two components: +- **Static site**: Served from `docs/` directory (configured via `vercel.json` `outputDirectory`) +- **Serverless API**: Three functions in `api/` for Razorpay checkout: + - `GET /api/config` — serves the public Razorpay Key ID + - `POST /api/create-order` — creates a Razorpay order (uses `RAZORPAY_KEY_SECRET`) + - `POST /api/verify-payment` — verifies payment signatures + +Environment variables (`RAZORPAY_KEY_ID`, `RAZORPAY_KEY_SECRET`) are configured in the Vercel Dashboard, not committed to the repo. + +The `api/package.json` declares serverless-specific dependencies (only `razorpay` SDK). This is separate from the root `package.json` which is for the VS Code extension. + +For local development, use `node scripts/dev-server.js` which serves `docs/` statically and mounts the `api/` handlers as Express routes, or use `npx vercel dev` for a full Vercel emulation. + +Custom domain (`pgstudio.astrx.dev`) is managed via Vercel Dashboard → Domains. + ## Maintenance Rules When editing this site: @@ -105,7 +124,10 @@ When editing this site: - Treat this as a simulated product experience; avoid replacing interaction with static text. - Maintain install CTAs in both topbar and minimized overview. - Verify both desktop and mobile toggle flows after major UI changes. +- Never commit `RAZORPAY_KEY_SECRET` or live credentials; use Vercel environment variables. +- When adding new API endpoints, add them to both `api/` and `scripts/dev-server.js`. ## Known Environment Note This review is based on source-level inspection in this workspace. Runtime browser introspection from the agent was unavailable because chat browser tools are not enabled in the current VS Code environment. + diff --git a/docs/html/minimized-overview.html b/docs/html/minimized-overview.html index 4f577c9..3d38469 100644 --- a/docs/html/minimized-overview.html +++ b/docs/html/minimized-overview.html @@ -284,6 +284,24 @@