Initial commit: Pokerface sprint planning poker for Jira
Full-stack app with Express/Socket.io backend, React frontend, NATS JetStream for state, and Atlassian Jira OAuth integration. Includes security hardening: NATS auth support, KV bucket TTL enforcement, CAS retry for race conditions, error message sanitization, and OAuth state stored in NATS KV. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
commit
fdd9ba8d56
36 changed files with 7596 additions and 0 deletions
239
frontend/src/components/LegalPage.jsx
Normal file
239
frontend/src/components/LegalPage.jsx
Normal file
|
|
@ -0,0 +1,239 @@
|
|||
export default function LegalPage({ page, dark, onBack }) {
|
||||
return (
|
||||
<div className="min-h-screen flex flex-col" style={{ background: dark ? '#09090b' : '#f0f1f5' }}>
|
||||
<header className="flex items-center gap-3 px-5 py-3 shrink-0">
|
||||
<button
|
||||
onClick={onBack}
|
||||
className="text-sm font-medium px-3 py-1 border-none cursor-pointer transition-colors"
|
||||
style={{
|
||||
color: dark ? '#94a3b8' : '#64748b',
|
||||
background: dark ? '#1e293b' : '#e2e8f0'
|
||||
}}
|
||||
>
|
||||
← Back
|
||||
</button>
|
||||
<span className="font-syne font-bold text-sm tracking-tight" style={{ color: dark ? '#fff' : '#0f172a' }}>
|
||||
POKERFACE
|
||||
</span>
|
||||
</header>
|
||||
|
||||
<main className="flex-1 px-5 py-6 max-w-2xl mx-auto w-full">
|
||||
{page === 'terms' && <TermsOfService dark={dark} />}
|
||||
{page === 'privacy' && <PrivacyPolicy dark={dark} />}
|
||||
{page === 'support' && <Support dark={dark} />}
|
||||
</main>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function Heading({ children, dark }) {
|
||||
return <h1 className="text-2xl font-bold mb-4 mt-0" style={{ color: dark ? '#fff' : '#0f172a' }}>{children}</h1>;
|
||||
}
|
||||
|
||||
function SubHeading({ children, dark }) {
|
||||
return <h2 className="text-base font-semibold mt-6 mb-2" style={{ color: dark ? '#e2e8f0' : '#1e293b' }}>{children}</h2>;
|
||||
}
|
||||
|
||||
function P({ children, dark }) {
|
||||
return <p className="text-sm leading-relaxed my-2" style={{ color: dark ? '#94a3b8' : '#475569' }}>{children}</p>;
|
||||
}
|
||||
|
||||
function Li({ children, dark }) {
|
||||
return <li className="text-sm leading-relaxed my-1" style={{ color: dark ? '#94a3b8' : '#475569' }}>{children}</li>;
|
||||
}
|
||||
|
||||
function TermsOfService({ dark }) {
|
||||
return (
|
||||
<>
|
||||
<Heading dark={dark}>Terms of Service</Heading>
|
||||
<P dark={dark}><em>Last updated: February 2026</em></P>
|
||||
|
||||
<SubHeading dark={dark}>1. Acceptance</SubHeading>
|
||||
<P dark={dark}>
|
||||
By accessing or using Pokerface ("the Service"), you agree to these terms.
|
||||
If you do not agree, do not use the Service.
|
||||
</P>
|
||||
|
||||
<SubHeading dark={dark}>2. Description</SubHeading>
|
||||
<P dark={dark}>
|
||||
Pokerface is a free sprint planning poker tool that integrates with Atlassian Jira.
|
||||
It is provided as a convenience for agile teams to facilitate estimation sessions.
|
||||
</P>
|
||||
|
||||
<SubHeading dark={dark}>3. No Warranty</SubHeading>
|
||||
<P dark={dark}>
|
||||
THE SERVICE IS PROVIDED "AS IS" AND "AS AVAILABLE" WITHOUT WARRANTIES OF ANY KIND,
|
||||
WHETHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE. THIS INCLUDES, WITHOUT LIMITATION,
|
||||
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
|
||||
NON-INFRINGEMENT. NO ADVICE OR INFORMATION, WHETHER ORAL OR WRITTEN, OBTAINED FROM
|
||||
THE SERVICE SHALL CREATE ANY WARRANTY NOT EXPRESSLY STATED HEREIN.
|
||||
</P>
|
||||
|
||||
<SubHeading dark={dark}>4. Limitation of Liability</SubHeading>
|
||||
<P dark={dark}>
|
||||
TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT SHALL THE DEVELOPERS,
|
||||
OPERATORS, OR CONTRIBUTORS OF POKERFACE BE LIABLE FOR ANY INDIRECT, INCIDENTAL,
|
||||
SPECIAL, CONSEQUENTIAL, OR PUNITIVE DAMAGES, OR ANY LOSS OF PROFITS, DATA, USE, OR
|
||||
GOODWILL, HOWEVER CAUSED AND UNDER ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY, OR OTHERWISE, ARISING OUT OF OR IN
|
||||
CONNECTION WITH YOUR ACCESS TO OR USE OF (OR INABILITY TO USE) THE SERVICE.
|
||||
</P>
|
||||
<P dark={dark}>
|
||||
THE TOTAL AGGREGATE LIABILITY OF THE SERVICE OPERATORS FOR ALL CLAIMS RELATING TO
|
||||
THE SERVICE SHALL NOT EXCEED ZERO EUROS (EUR 0.00).
|
||||
</P>
|
||||
|
||||
<SubHeading dark={dark}>5. No Guarantee of Availability</SubHeading>
|
||||
<P dark={dark}>
|
||||
The Service may be modified, suspended, or discontinued at any time without notice.
|
||||
We are under no obligation to maintain, support, or update the Service.
|
||||
</P>
|
||||
|
||||
<SubHeading dark={dark}>6. User Responsibilities</SubHeading>
|
||||
<P dark={dark}>
|
||||
You are responsible for your use of the Service and any data you transmit through it.
|
||||
You must comply with Atlassian's terms of service when using Jira integration features.
|
||||
</P>
|
||||
|
||||
<SubHeading dark={dark}>7. Third-Party Services</SubHeading>
|
||||
<P dark={dark}>
|
||||
Pokerface integrates with Atlassian Jira via OAuth. Your use of Jira is governed by
|
||||
Atlassian's own terms and privacy policy. We are not responsible for any third-party
|
||||
service availability or behavior.
|
||||
</P>
|
||||
|
||||
<SubHeading dark={dark}>8. Changes to Terms</SubHeading>
|
||||
<P dark={dark}>
|
||||
These terms may be updated at any time. Continued use of the Service after changes
|
||||
constitutes acceptance of the revised terms.
|
||||
</P>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function PrivacyPolicy({ dark }) {
|
||||
return (
|
||||
<>
|
||||
<Heading dark={dark}>Privacy Policy</Heading>
|
||||
<P dark={dark}><em>Last updated: February 2026</em></P>
|
||||
|
||||
<SubHeading dark={dark}>1. What Data We Collect</SubHeading>
|
||||
<P dark={dark}>
|
||||
When you sign in with Jira, we receive the following information from Atlassian via OAuth:
|
||||
</P>
|
||||
<ul className="pl-5 my-2">
|
||||
<Li dark={dark}><strong>Jira account ID</strong> — your unique Atlassian identifier</Li>
|
||||
<Li dark={dark}><strong>Display name</strong> — your Jira profile name</Li>
|
||||
<Li dark={dark}><strong>Avatar URL</strong> — a link to your Jira profile picture</Li>
|
||||
<Li dark={dark}><strong>Email address</strong> — your Jira account email</Li>
|
||||
<Li dark={dark}><strong>Cloud ID and site URL</strong> — identifies your Jira workspace</Li>
|
||||
<Li dark={dark}><strong>OAuth tokens</strong> — access and refresh tokens for Jira API calls</Li>
|
||||
</ul>
|
||||
<P dark={dark}>
|
||||
During poker sessions, we temporarily store:
|
||||
</P>
|
||||
<ul className="pl-5 my-2">
|
||||
<Li dark={dark}>Room and session metadata (project name, sprint name, issue keys)</Li>
|
||||
<Li dark={dark}>Participant names and avatar URLs</Li>
|
||||
<Li dark={dark}>Votes submitted during estimation sessions</Li>
|
||||
</ul>
|
||||
|
||||
<SubHeading dark={dark}>2. How We Use Your Data</SubHeading>
|
||||
<P dark={dark}>
|
||||
Your data is used solely to operate the poker planning functionality:
|
||||
authenticating you with Jira, displaying participants in sessions, recording votes,
|
||||
and writing agreed estimates back to Jira issues. We do not use your data for
|
||||
analytics, advertising, profiling, or any other purpose.
|
||||
</P>
|
||||
|
||||
<SubHeading dark={dark}>3. Data Storage and Retention</SubHeading>
|
||||
<P dark={dark}>
|
||||
All data is stored in NATS JetStream key-value buckets with automatic time-to-live (TTL) expiration:
|
||||
</P>
|
||||
<ul className="pl-5 my-2">
|
||||
<Li dark={dark}><strong>OAuth connections</strong> — automatically deleted after 24 hours</Li>
|
||||
<Li dark={dark}><strong>Rooms and sessions</strong> — automatically deleted after 24 hours</Li>
|
||||
<Li dark={dark}><strong>OAuth state tokens</strong> — automatically deleted after 10 minutes</Li>
|
||||
</ul>
|
||||
<P dark={dark}>
|
||||
There is no long-term database. All session data is ephemeral and automatically purged
|
||||
by TTL. When a poker session is saved, the session data is deleted immediately.
|
||||
</P>
|
||||
|
||||
<SubHeading dark={dark}>4. Cookies</SubHeading>
|
||||
<P dark={dark}>
|
||||
Pokerface uses a single, strictly functional cookie:
|
||||
</P>
|
||||
<ul className="pl-5 my-2">
|
||||
<Li dark={dark}>
|
||||
<strong>pokerface_session</strong> — an HttpOnly, Secure, SameSite=Lax JWT cookie
|
||||
that contains your Jira account ID, cloud ID, display name, and avatar URL. It
|
||||
expires after 24 hours. This cookie is required for the application to function.
|
||||
</Li>
|
||||
</ul>
|
||||
<P dark={dark}>
|
||||
We do not use tracking cookies, analytics cookies, or any third-party cookies.
|
||||
A dark mode preference is stored in your browser's localStorage (not a cookie)
|
||||
and never sent to our servers.
|
||||
</P>
|
||||
|
||||
<SubHeading dark={dark}>5. Data Sharing</SubHeading>
|
||||
<P dark={dark}>
|
||||
We do not sell, share, or transfer your personal data to any third party.
|
||||
The only external communication is between our backend and Atlassian's Jira API,
|
||||
using the OAuth tokens you authorized, to read project/sprint data and write
|
||||
estimates back to issues.
|
||||
</P>
|
||||
|
||||
<SubHeading dark={dark}>6. Data Security</SubHeading>
|
||||
<P dark={dark}>
|
||||
All traffic is encrypted via HTTPS in production. Session cookies are marked HttpOnly
|
||||
and Secure. Security headers (HSTS, X-Frame-Options DENY, nosniff) are applied to all
|
||||
responses. OAuth tokens are stored server-side only and never exposed to the browser.
|
||||
</P>
|
||||
|
||||
<SubHeading dark={dark}>7. Your Rights</SubHeading>
|
||||
<P dark={dark}>
|
||||
Since all data expires automatically within 24 hours, there is no persistent personal
|
||||
data to request deletion of. You can sign out at any time to clear your session cookie.
|
||||
Revoking the Pokerface OAuth connection in your Atlassian account settings will
|
||||
invalidate all stored tokens.
|
||||
</P>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function Support({ dark }) {
|
||||
return (
|
||||
<>
|
||||
<Heading dark={dark}>Support</Heading>
|
||||
<P dark={dark}><em>Last updated: February 2026</em></P>
|
||||
|
||||
<SubHeading dark={dark}>About Pokerface</SubHeading>
|
||||
<P dark={dark}>
|
||||
Pokerface is a free, open tool for sprint planning poker with Jira integration.
|
||||
It is provided as-is, with no guarantees of availability, support, or maintenance.
|
||||
</P>
|
||||
|
||||
<SubHeading dark={dark}>No Formal Support</SubHeading>
|
||||
<P dark={dark}>
|
||||
This product does not come with dedicated support, SLAs, or guaranteed response times.
|
||||
There is no helpdesk, ticketing system, or support team.
|
||||
</P>
|
||||
|
||||
<SubHeading dark={dark}>Best-Effort Assistance</SubHeading>
|
||||
<P dark={dark}>
|
||||
If you encounter a bug or issue, you may reach out via the project's repository.
|
||||
Any assistance is provided on a best-effort basis at the maintainer's discretion.
|
||||
</P>
|
||||
|
||||
<SubHeading dark={dark}>Alternatives</SubHeading>
|
||||
<P dark={dark}>
|
||||
If Pokerface does not meet your needs, there are many alternative planning poker tools
|
||||
available in the Atlassian Marketplace and elsewhere. You are free to stop using
|
||||
Pokerface at any time — simply sign out and revoke the OAuth connection in your
|
||||
Atlassian account settings.
|
||||
</P>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue