Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,13 @@ FIXES_APPLIED.md
.agents/
skills-lock.json
graphify-out/
.superpowers/
.superpowers/
docs/roadmap/
docs/plans/
docs/specs/
docs/plan/
.commandcode/
test/
.vercel
.env
.env.local
9 changes: 9 additions & 0 deletions .kilo/agent-manager.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"worktrees": {},
"sessions": {},
"tabOrder": {
"local": [
"pending:1"
]
}
}
3 changes: 2 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"typescript.tsdk": "node_modules/typescript/lib",
"typescript.enablePromptUseWorkspaceTsdk": true
"typescript.enablePromptUseWorkspaceTsdk": true,
"makefile.configureOnOpen": true
}
5 changes: 4 additions & 1 deletion .vscodeignore
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ venv/**
.cursor/
.nightly/
.kiro/
.kilo/
.c8rc.phase-handlers.json
.c8rc.phase-utils.json
.c8rc.phase-report.json
Expand All @@ -69,4 +70,6 @@ FIXES_APPLIED.md
review-the-current-codebase-shimmering-bee.md
.github/
.coverage/
.coverage-unit/
.coverage-unit/
packages/
graphify-out/
42 changes: 42 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
8 changes: 8 additions & 0 deletions api/config.js
Original file line number Diff line number Diff line change
@@ -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
});
};
63 changes: 63 additions & 0 deletions api/create-order.js
Original file line number Diff line number Diff line change
@@ -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' });
}
};
6 changes: 6 additions & 0 deletions api/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"private": true,
"dependencies": {
"razorpay": "^2.9.0"
}
}
44 changes: 44 additions & 0 deletions api/verify-payment.js
Original file line number Diff line number Diff line change
@@ -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' });
}
};
2 changes: 1 addition & 1 deletion docs/CNAME
Original file line number Diff line number Diff line change
@@ -1 +1 @@
pgstudio.astrx.dev
# This file is no longer needed. Custom domain is managed via Vercel Dashboard.
File renamed without changes.
26 changes: 24 additions & 2 deletions docs/WEBSITE_CONTEXT.md
Original file line number Diff line number Diff line change
@@ -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

Expand Down Expand Up @@ -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:
Expand All @@ -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.

18 changes: 18 additions & 0 deletions docs/html/minimized-overview.html
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,24 @@ <h2 class="section-title" id="landing-price-title">Simple, transparent pricing</
</ul>
<a class="pricing-cta primary" href="https://marketplace.visualstudio.com/items?itemName=ric-v.postgres-explorer" target="_blank" rel="noopener noreferrer">Install Free</a>
</div>
<div class="pricing-card pricing-card-pro" style="border: 1px solid var(--accent-color, #4d5efc); position: relative; box-shadow: 0 4px 20px rgba(77, 94, 252, 0.15);">
<span class="pricing-badge" style="position: absolute; top: -12px; right: 20px; background: var(--accent-color, #4d5efc); color: white; padding: 2px 10px; border-radius: 12px; font-size: 10px; font-weight: bold; letter-spacing: 0.5px;">RECOMMENDED</span>
<div class="pricing-name">Pro Sponsor</div>
<div class="pricing-desc">Support continuous development and unlock pre-release features</div>
<div class="pricing-amount">₹1.00 <span class="period">/ one-time</span></div>
<ul class="pricing-items">
<li>Everything in Community</li>
<li>Sponsor status on GitHub and Discord</li>
<li>Exclusive access to monthly beta builds</li>
<li>Early access to schema diff visual tools</li>
<li>Early access to Teams cloud synchronization</li>
<li>Direct developer feedback channel</li>
</ul>
<button class="pricing-cta primary" id="btn-razorpay-checkout" type="button" style="width: 100%; border: none; cursor: pointer; display: flex; align-items: center; justify-content: center; gap: 8px;">
<span>Sponsor with Razorpay</span>
<span style="font-size: 14px;">⚡</span>
</button>
</div>
<div class="pricing-card pricing-card-roadmap">
<div class="pricing-name">Teams roadmap</div>
<div class="pricing-desc">Commercial tiers are not sold yet — follow progress on GitHub.</div>
Expand Down
3 changes: 3 additions & 0 deletions docs/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,9 @@
<script src="js/tour.js"></script>
<script src="js/visuals.js"></script>
<script src="js/landing-capabilities.js"></script>
<!-- Razorpay Checkout Integration -->
<script src="https://checkout.razorpay.com/v1/checkout.js"></script>
<script src="js/checkout.js"></script>
<script src="js/bootstrap.js"></script>
</body>

Expand Down
Loading
Loading