Skip to content

Commit e0dbcb5

Browse files
authored
feat: persona-driven trust & info-scent fixes (#28)
* feat: persona-driven trust & info-scent fixes across the site Addresses the visitor-persona audit findings in one pass: First-time developer (info scent): - Homepage gains a feature bridge — an in-fiction "SELECT name, summary FROM features LIMIT 4;" mini result set (NL2SQL Copilot, AI Query Safety, Visual EXPLAIN, Data Masking) linking to all 18 features Evaluating DBA (consistency + trust): - New /security page consolidating the honest security model: OIDC+PKCE, RBAC, env-var seed credentials, TLS/SSH tunnels, display-level masking (stated as such), supply-chain checksums, and the SECURITY.md disclosure path - Studio version now fetched from GitHub releases at build time (bare-semver app tags only, chart releases filtered, memoized, with fallback) and rendered as "studio:x.y.z" in the StatusBar and as JSON-LD softwareVersion — replaces three conflicting hardcoded numbers - Engine list single-sourced in src/data/engines.ts (hero + JSON-LD) - Compare page gains a methodology footnote with last-check date and a corrections channel DevOps engineer: - /get-started gains "Next: connect your first database" — four steps with least-privilege guidance and links to the seed-connections guide and /security - /features ends with a closing CTA instead of a dead end Customer (honest licensing): - Platform pages now state the real model: closed source, beta, self-hosted, per-organization enterprise licenses, no online sales yet, with a "talk to us" contact path (LinkedIn) - Home family card: "Managed for teams" -> "Self-hosted for enterprises" - FAQ +2: "How is LibreDB Platform licensed?" and "Why sponsor LibreDB?" JSON-LD sameAs now includes X/YouTube/Instagram/Reddit. * feat: add the 70s "connect your own database" video to /get-started The video sits inside the "Next: connect your first database" panel as the written steps in motion — same click-to-load nocookie facade as the homepage promo (self-hosted poster, zero third-party bytes until play). Its flow mirrors the steps 1:1: New Connection -> pick engine -> host & credentials -> SSL/SSH -> Test Connection -> first query. Also fixes three whitespace-collapse spots in the step copy where prettier's line breaks ate the space before inline spans. * design: move the get-started video to the top of the page The video opens with the install itself ("docker run ..."), so it is the whole page's journey — install, connect, first query — not just the connect panel's. It now sits directly under the page header, above the fold: watch 70 seconds first, then follow the steps. The connect panel keeps its written steps and links. * chore: bump version to 0.7.1 * fix: address Copilot review — derive every engine/count surface, harden version fetch All five findings verified valid (single-source consistency class): - studio-version fetch: per_page 15 -> 30 and a 10s AbortSignal timeout so a slow network can't hang the static build - FAQ pageDescription now mentions Platform licensing and sponsorship, matching the section's actual content - get-started step 2 engine list derives from ENGINES - home feature-bridge counts derive from sectionById['features'].rows - JSON-LD keywords derive from ENGINES
1 parent 2fdbcd6 commit e0dbcb5

16 files changed

Lines changed: 388 additions & 17 deletions

‎package.json‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "libredb-studio-website",
33
"type": "module",
4-
"version": "0.7.0",
4+
"version": "0.7.1",
55
"scripts": {
66
"dev": "astro dev",
77
"build": "node scripts/sync-docker-compose.mjs && astro build",

‎public/video/connect-poster.jpg‎

101 KB
Loading

‎src/components/sections/CompareSection.astro‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,19 @@ const exportRows = rows.map((r) => ({
122122
))
123123
}
124124
</div>
125+
126+
<p class="mt-6 text-[13px] leading-relaxed">
127+
<span class="sql-com">
128+
-- methodology: scored by the LibreDB team from each tool's public docs and pricing pages (last check:
129+
2026-07-15). spotted an error?
130+
</span>
131+
<a
132+
href="https://github.com/libredb/libredb-studio/issues"
133+
target="_blank"
134+
rel="noopener noreferrer"
135+
class="text-muted hover:text-fg">file an issue →</a
136+
>
137+
</p>
125138
</div>
126139
<script
127140
type="application/json"

‎src/components/sections/FaqSection.astro‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,14 @@ const faqs: QA[] = [
4545
q: 'How does it compare to pgAdmin or DBeaver?',
4646
a: 'Unlike pgAdmin (PostgreSQL only) or DBeaver (desktop app), LibreDB Studio is web-based, mobile-ready, and deeply AI-powered. Beyond NL2SQL, we offer AI Query Safety Analysis, AI Query Explainer, AI Query Autopilot, AI Data Profiler, ORM Code Generator, Test Data Generator, Interactive Pivot Tables, ER Diagrams, Database Documentation, and automatic Data Masking with RBAC enforcement - features no desktop IDE provides. Zero installation, works on any device.',
4747
},
48+
{
49+
q: 'How is LibreDB Platform licensed?',
50+
a: 'Platform is the closed-source enterprise layer of the open-core model, currently in beta. It is licensed per organization and self-hosted on your own infrastructure — there is no online purchase or hosted subscription yet. Licensing conversations happen directly with the team (reach us on LinkedIn), and Platform revenue funds the open-source work on Studio and the LibreDB engine. Studio itself stays MIT and free forever, regardless.',
51+
},
52+
{
53+
q: 'Why sponsor LibreDB?',
54+
a: 'Studio is MIT-licensed and free forever — no premium tier is coming to paywall it. Sponsorship (github.com/sponsors/libredb) directly funds what you already use: maintenance across seven database engines, security reviews, the release pipeline that ships Docker, Helm, npm, Homebrew and Snap packages on every release, and development of the open-source LibreDB engine. If Studio saves your team an hour a month, a sponsorship is the cheapest way to keep it alive and independent.',
55+
},
4856
];
4957
---
5058

‎src/components/sections/FeaturesSection.astro‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,23 @@ const features: Feature[] = [
135135
))
136136
}
137137
</div>
138+
139+
<!-- Closing CTA — long result sets shouldn't end in a dead end -->
140+
<section class="mt-10 flex flex-wrap gap-3">
141+
<a
142+
href="https://app.libredb.org"
143+
target="_blank"
144+
rel="noopener noreferrer"
145+
class="inline-flex items-center gap-2 rounded-md bg-primary px-5 py-2.5 text-sm font-medium text-white transition-colors hover:bg-primary-bright"
146+
>
147+
<span aria-hidden="true">▶</span> Try them live
148+
</a>
149+
<a
150+
href="/get-started"
151+
class="inline-flex items-center gap-2 rounded-md border border-edge-strong px-5 py-2.5 text-sm font-medium text-fg transition-colors hover:bg-raised"
152+
>Get started <span aria-hidden="true">→</span></a
153+
>
154+
</section>
138155
</div>
139156
<script
140157
type="application/json"

‎src/components/sections/GetStartedSection.astro‎

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
---
22
import SectionHeader from './SectionHeader.astro';
3+
import PromoVideo from './PromoVideo.astro';
4+
import { ENGINES } from '../../data/engines';
5+
6+
const engineList = `${ENGINES.slice(0, -1).join(', ')}, or ${ENGINES.at(-1)}`;
37
48
interface Line {
59
kind: 'cmd' | 'comment' | 'out';
@@ -55,6 +59,18 @@ const copyText = (s: Step) =>
5559
<div class="mx-auto max-w-6xl">
5660
<SectionHeader title="Get started in minutes" subtitle="Up and running with three simple steps." />
5761

62+
<!-- The whole journey in motion, before the steps (click-to-load facade) -->
63+
<div class="mb-8 max-w-3xl">
64+
<PromoVideo
65+
videoId="KazHTclbiSQ"
66+
title="Connect Your Own Database in LibreDB Studio"
67+
poster="/video/connect-poster.jpg"
68+
/>
69+
<p class="mt-2 text-[13px] leading-relaxed">
70+
<span class="sql-com">-- 70s: install → connect your database → first query. the steps below, in motion.</span>
71+
</p>
72+
</div>
73+
5874
<div class="grid grid-cols-1 gap-4 lg:grid-cols-3">
5975
{
6076
steps.map((s) => (
@@ -141,6 +157,38 @@ const copyText = (s: Step) =>
141157
<a href="/deploy" class="text-[13px] text-primary hover:underline">Explore all deploy options →</a>
142158
</div>
143159
</div>
160+
161+
<!-- The first real step AFTER the app is running -->
162+
<section class="mt-10 border border-edge bg-panel p-6">
163+
<h3 class="text-[15px] font-semibold text-bright">Next: connect your first database</h3>
164+
<ol class="mt-4 flex list-none flex-col gap-3 text-[13px] leading-relaxed text-muted">
165+
<li>
166+
<span class="text-faint select-none">1&nbsp;</span> Log in and open{' '}
167+
<span class="font-semibold text-fg">Connections → New connection</span>.
168+
</li>
169+
<li><span class="text-faint select-none">2&nbsp;</span> Pick your engine — {engineList}.</li>
170+
<li>
171+
<span class="text-faint select-none">3&nbsp;</span> Enter host and credentials.{' '}
172+
<span class="text-dim">Start with a dedicated read-only database account</span> — least privilege first, write access
173+
when you actually need it. Databases behind a firewall connect over an SSH tunnel.
174+
</li>
175+
<li>
176+
<span class="text-faint select-none">4&nbsp;</span> Deploying for a team? Define{' '}
177+
<span class="font-semibold text-fg">seed connections</span> whose credentials resolve from environment variables at
178+
runtime — secrets stay in your secret manager, never in a config file.
179+
</li>
180+
</ol>
181+
182+
<div class="mt-5 flex flex-wrap gap-4 text-[13px]">
183+
<a
184+
href="https://github.com/libredb/libredb-studio/blob/main/docs/SEED_CONNECTIONS.md"
185+
target="_blank"
186+
rel="noopener noreferrer"
187+
class="text-primary hover:underline">Seed connections guide →</a
188+
>
189+
<a href="/security" class="text-primary hover:underline">How credentials are handled →</a>
190+
</div>
191+
</section>
144192
</div>
145193
<script
146194
type="application/json"

‎src/components/sections/HomeSection.astro‎

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,20 @@
11
---
22
import PromoVideo from './PromoVideo.astro';
3+
import { ENGINES } from '../../data/engines';
4+
import { sectionById } from '../../data/sections';
35
46
const DEMO = 'https://app.libredb.org';
57
6-
const databases = ['PostgreSQL', 'MySQL', 'Oracle', 'SQL Server', 'SQLite', 'MongoDB', 'Redis'];
8+
const databases = ENGINES;
9+
const featureRows = sectionById['features'].rows;
10+
11+
// Info-scent bridge to /features: four flagship rows of the full result set.
12+
const flagship = [
13+
{ name: 'NL2SQL Copilot', line: 'Plain English in, executable SQL out.' },
14+
{ name: 'AI Query Safety', line: 'Risk analysis before destructive queries run.' },
15+
{ name: 'Visual EXPLAIN', line: 'Graphical plans with plain-language notes.' },
16+
{ name: 'Data Masking', line: 'Sensitive columns masked in grid and exports.' },
17+
];
718
---
819

920
<div class="mx-auto max-w-5xl px-1">
@@ -62,6 +73,27 @@ const databases = ['PostgreSQL', 'MySQL', 'Oracle', 'SQL Server', 'SQLite', 'Mon
6273
</p>
6374
</div>
6475

76+
<!-- Feature bridge: a taste of the result set behind /features -->
77+
<div class="mt-12 border-t border-edge pt-8">
78+
<p class="text-[13px]">
79+
<span class="sql-kw">SELECT</span> name, summary <span class="sql-kw">FROM</span> features{' '}
80+
<span class="sql-kw">LIMIT</span>{' '}<span class="sql-num">4</span>;
81+
</p>
82+
<div class="mt-4 grid grid-cols-1 gap-px overflow-hidden border border-edge bg-edge sm:grid-cols-2 lg:grid-cols-4">
83+
{
84+
flagship.map((f) => (
85+
<div class="bg-panel p-4">
86+
<h3 class="text-[13px] font-semibold text-bright">{f.name}</h3>
87+
<p class="mt-1.5 text-[12px] leading-relaxed text-dim">{f.line}</p>
88+
</div>
89+
))
90+
}
91+
</div>
92+
<a href="/features" class="mt-3 inline-block text-[13px] text-muted hover:text-fg">
93+
… {featureRows - flagship.length} more rows — see all {featureRows} features <span aria-hidden="true">→</span>
94+
</a>
95+
</div>
96+
6597
<!-- The LibreDB family / open-core (secondary; Studio stays the hero above) -->
6698
<div class="mt-14 border-t border-edge pt-8">
6799
<p class="text-[11px] tracking-wider text-faint uppercase">The LibreDB family — one core, three products</p>
@@ -90,7 +122,7 @@ const databases = ['PostgreSQL', 'MySQL', 'Oracle', 'SQL Server', 'SQLite', 'Mon
90122
<span class="text-[11px] text-dim">beta</span>
91123
</div>
92124
<p class="mt-2 text-[12px] leading-relaxed text-dim">
93-
Managed for teams — Database Access Governance: authorized, audited, multi-tenant.
125+
Self-hosted for enterprises — Database Access Governance: authorized, audited, multi-tenant.
94126
</p>
95127
</a>
96128
</div>

‎src/components/sections/PlatformSection.astro‎

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,11 @@ const capabilities = [
2020
name: 'Query audit log',
2121
detail: 'Every query logged with user, timing, and status — full accountability.',
2222
},
23-
{ name: 'Plans', detail: 'Free, Team, Business, and Enterprise tiers — runtime-configurable.' },
23+
{
24+
name: 'Enterprise licensing',
25+
detail:
26+
'Self-hosted, per-organization licenses during beta — tiers are runtime-configurable per license. No online sales yet.',
27+
},
2428
{
2529
name: 'SSO / OIDC',
2630
detail: 'Vendor-agnostic single sign-on (Auth0, Keycloak, Okta, Azure AD).',
@@ -29,8 +33,10 @@ const capabilities = [
2933
3034
const openCore = [
3135
{ tier: 'Studio', line: 'OSS · free · self-hosted · community', cls: 'text-primary' },
32-
{ tier: 'Platform', line: 'closed · paid · cloud · enterprise', cls: 'text-ai' },
36+
{ tier: 'Platform', line: 'closed source · beta · self-hosted · enterprise license', cls: 'text-ai' },
3337
];
38+
39+
const LINKEDIN = 'https://www.linkedin.com/company/libredb';
3440
---
3541

3642
<div class="mx-auto max-w-5xl">
@@ -45,7 +51,8 @@ const openCore = [
4551
<span class="text-ai">Governance</span> Platform
4652
</h1>
4753
<p class="mt-5 max-w-2xl text-[15px] leading-relaxed text-muted">
48-
Centralized, authorized, audited database access for teams and enterprises — the managed, team form of LibreDB.
54+
Centralized, authorized, audited database access for teams and enterprises — the governed, team form of LibreDB,
55+
self-hosted on your infrastructure.
4956
</p>
5057

5158
<!-- Problem callout -->
@@ -79,7 +86,7 @@ const openCore = [
7986
<div class="mt-10">
8087
<SectionHeader
8188
title="Open core"
82-
subtitle="Studio is free & open; Platform is the managed layer that funds the open-source work."
89+
subtitle="Studio is free & open; Platform is the commercial layer that funds the open-source work."
8390
/>
8491
<div class="grid grid-cols-1 gap-px overflow-hidden border border-edge bg-edge sm:grid-cols-2">
8592
{
@@ -98,9 +105,28 @@ const openCore = [
98105
</p>
99106
</div>
100107

108+
<!-- How to get it: honest licensing model, with a human contact path -->
109+
<div class="mt-10 border-l-2 border-ai/60 bg-panel p-5">
110+
<h3 class="text-[15px] font-semibold text-bright">How Platform is sold today</h3>
111+
<p class="mt-2 max-w-2xl text-[13.5px] leading-relaxed text-dim">
112+
Platform is in beta and is licensed <span class="text-fg"
113+
>per organization, self-hosted on your infrastructure</span
114+
> — there is no online purchase or hosted subscription yet. Licensing conversations happen directly with the team, and
115+
beta partners shape the roadmap.
116+
</p>
117+
<a
118+
href={LINKEDIN}
119+
target="_blank"
120+
rel="noopener noreferrer"
121+
class="mt-4 inline-flex items-center gap-2 rounded-md border border-edge-strong px-4 py-2 text-[13px] font-medium text-fg transition-colors hover:bg-raised"
122+
>
123+
Talk to us about licensing <span aria-hidden="true">→</span>
124+
</a>
125+
</div>
126+
101127
<!-- CTA (the only external link) -->
102128
<div
103-
class="mt-10 flex flex-col items-start justify-between gap-4 border border-edge bg-panel p-6 sm:flex-row sm:items-center"
129+
class="mt-8 flex flex-col items-start justify-between gap-4 border border-edge bg-panel p-6 sm:flex-row sm:items-center"
104130
>
105131
<div>
106132
<h3 class="text-[16px] font-bold text-bright">Try the beta</h3>
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
---
2+
// The consolidated security page a DBA or security reviewer looks for before
3+
// letting a tool near production. Deliberately honest: it states what is
4+
// enforced where (and display-level vs server-side), never more.
5+
import SectionHeader from './SectionHeader.astro';
6+
7+
const SECURITY_MD = 'https://github.com/libredb/libredb-studio/blob/main/SECURITY.md';
8+
const SEED_DOCS = 'https://github.com/libredb/libredb-studio/blob/main/docs/SEED_CONNECTIONS.md';
9+
const OIDC_DOCS = 'https://github.com/libredb/libredb-studio/blob/main/docs/OIDC.md';
10+
11+
const controls = [
12+
{
13+
control: 'Authentication',
14+
detail:
15+
'OpenID Connect SSO (Auth0, Keycloak, Okta, Azure AD or any OIDC provider) using Authorization Code Flow with PKCE. Sessions ride JWTs in httpOnly cookies — no tokens in localStorage.',
16+
href: OIDC_DOCS,
17+
linkLabel: 'OIDC guide',
18+
},
19+
{
20+
control: 'Authorization',
21+
detail:
22+
'Role-based access control with per-connection visibility scoping — a connection can be exposed to admins only, to users, or to everyone. Roles map from your identity provider claims.',
23+
},
24+
{
25+
control: 'Database credentials',
26+
detail:
27+
'Seed connections resolve ${ENV_VAR} placeholders at runtime, so secrets live in your environment or secret manager — never in a config file. Pair each connection with a dedicated least-privilege database account (read-only to start).',
28+
href: SEED_DOCS,
29+
linkLabel: 'Seed connections',
30+
},
31+
{
32+
control: 'Transport',
33+
detail:
34+
'TLS between browser and app; TLS and SSH tunnels from the app to your databases — including databases behind firewalls that never get public exposure.',
35+
},
36+
{
37+
control: 'Data masking',
38+
detail:
39+
'Sensitive columns (email, phone, SSN, financial data) are detected and masked across the grid, exports, and clipboard with RBAC enforcement. Masking is display-level — combine it with database-side grants for hard guarantees.',
40+
},
41+
{
42+
control: 'Self-hosting & isolation',
43+
detail:
44+
'Self-hosting is a first-class citizen: run it on your infrastructure, inside your network, behind your VPN. Nothing needs to leave your perimeter — including AI, which can run fully local via Ollama or LM Studio.',
45+
},
46+
{
47+
control: 'Supply chain',
48+
detail:
49+
'MIT-licensed source you can audit line by line. Every release ships SHA256 checksums; CI runs CodeQL and SonarCloud. Images are published to GHCR with immutable version tags.',
50+
},
51+
];
52+
---
53+
54+
<div class="mx-auto max-w-5xl">
55+
<SectionHeader
56+
title="Security model"
57+
subtitle="What is enforced, where it is enforced, and how to reach us when something isn't."
58+
/>
59+
60+
<div class="flex flex-col gap-px overflow-hidden border border-edge bg-edge">
61+
{
62+
controls.map((c) => (
63+
<article class="grid grid-cols-1 gap-2 bg-panel p-5 sm:grid-cols-[180px_1fr] sm:gap-6">
64+
<h3 class="text-[13px] font-semibold tracking-wide text-bright uppercase">{c.control}</h3>
65+
<div>
66+
<p class="text-[13px] leading-relaxed text-muted">{c.detail}</p>
67+
{c.href && (
68+
<a
69+
href={c.href}
70+
target="_blank"
71+
rel="noopener noreferrer"
72+
class="mt-1.5 inline-block text-[12px] text-primary hover:text-primary-bright"
73+
>
74+
{c.linkLabel} <span aria-hidden="true">→</span>
75+
</a>
76+
)}
77+
</div>
78+
</article>
79+
))
80+
}
81+
</div>
82+
83+
<!-- Responsible disclosure -->
84+
<section class="mt-10 border-l-2 border-warn/60 bg-panel p-5">
85+
<h3 class="text-[15px] font-semibold text-bright">Found a vulnerability?</h3>
86+
<p class="mt-2 max-w-2xl text-[13px] leading-relaxed text-dim">
87+
Please report it privately — not in a public issue. The disclosure process, supported versions, and response
88+
commitments live in the repository's security policy.
89+
</p>
90+
<a
91+
href={SECURITY_MD}
92+
target="_blank"
93+
rel="noopener noreferrer"
94+
class="mt-4 inline-flex items-center gap-2 rounded-md border border-edge-strong px-4 py-2 text-[13px] font-medium text-fg transition-colors hover:bg-raised"
95+
>
96+
Read SECURITY.md <span aria-hidden="true">→</span>
97+
</a>
98+
</section>
99+
100+
<p class="mt-6 text-[13px] leading-relaxed">
101+
<span class="sql-com">-- honest by default: if a control is display-level, this page says so.</span>
102+
</p>
103+
</div>
104+
<script
105+
type="application/json"
106+
data-export-payload="security"
107+
data-export-filename="security.json"
108+
data-export-format="json"
109+
set:html={JSON.stringify(controls.map(({ control, detail }) => ({ control, detail })))}
110+
/>

0 commit comments

Comments
 (0)