Skip to content

Commit e965965

Browse files
authored
ENG-6439: SOC2 comp. page (#1448)
1 parent 02c4f50 commit e965965

File tree

7 files changed

+315
-0
lines changed

7 files changed

+315
-0
lines changed

pcweb/pages/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
from pcweb.route import Route
22
from .affiliates import affiliates as affiliates
3+
from .security import security as security
34
from .databricks.databricks import databricks_page as databricks_page
45
from .use_cases.use_cases import use_cases_page as use_cases_page
56
from .blog import blog_routes
67
from .customers.data.customers import customers_routes
8+
from .security.security import security as security
79
from .customers.landing import customers as customers
810
from .docs import doc_routes
911
from .errors import errors as errors

pcweb/pages/security/data.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
"""Security page data configuration."""
2+
3+
# Feature data organized by category
4+
SECURITY_FEATURES = {
5+
"Data Protection": [
6+
("Data Encryption", "AES-256 encryption at rest, TLS 1.2+ in transit."),
7+
("Database Backups", "Daily encrypted backups with 30-day retention."),
8+
("Data Segregation", "Customer data is logically isolated per tenant."),
9+
],
10+
"Product Security": [
11+
("Penetration Testing", "External tests conducted annually."),
12+
("Secure Development Lifecycle", "Code reviews, linting, and security scans."),
13+
("Dependency Management", "Automated scanning for vulnerabilities."),
14+
],
15+
"Enterprise Security": [
16+
("SSO/SAML", "Supports major identity providers for centralized auth."),
17+
("Granular Permissions", "Role-based access control across teams."),
18+
("Audit Logs", "Track every access and change in the system."),
19+
],
20+
"Data Privacy": [
21+
("GDPR & CCPA Ready", "Compliant data handling and user rights."),
22+
("Data Deletion Requests", "Users can request full data erasure."),
23+
("Privacy by Design", "Privacy baked into product architecture."),
24+
],
25+
}
26+
27+
# Trust services criteria for the grid cards
28+
TRUST_SERVICES_CRITERIA = [
29+
{
30+
"title": "Security",
31+
"description": "Protection of systems and data from unauthorized access through firewalls, multi-factor authentication, and continuous monitoring.",
32+
"icon": "shield",
33+
},
34+
{
35+
"title": "Availability",
36+
"description": "Ensures that systems are operational and accessible as promised, with redundancy, failover systems, and uptime monitoring in place.",
37+
"icon": "globe",
38+
},
39+
{
40+
"title": "Confidentiality",
41+
"description": "Restricts access to sensitive information using encryption, role-based access controls, and secure data handling policies.",
42+
"icon": "backend_auth",
43+
},
44+
{
45+
"title": "Processing Integrity",
46+
"description": "Guarantees that system operations are accurate, timely, and authorized, using code reviews, automated tests, and deployment controls.",
47+
"icon": "code_custom",
48+
},
49+
{
50+
"title": "Privacy",
51+
"description": "Covers the collection, use, retention, and disposal of personal information according to regulatory and contractual obligations.",
52+
"icon": "clipboard",
53+
}
54+
]
55+
56+
# Page content configuration
57+
PAGE_CONTENT = {
58+
"title": "Security, Compliance, and Trust at Reflex",
59+
"subtitle": "We're committed to protecting your data through enterprise-grade security practices and full SOC 2 compliance.",
60+
"showcase": {
61+
"title": "Secure by default",
62+
"subtitle": "SOC 2 compliant with enterprise-grade security and flexible deployment options.",
63+
"logos": [
64+
{"src": "/soc2.webp", "alt": "SOC 2 Compliance"},
65+
{"src": "/databricks-partner.svg", "alt": "Databricks Partner"}
66+
]
67+
},
68+
"table": {
69+
"title": "Enterprise-Grade Security at Every Layer",
70+
"description": "From data protection to privacy compliance, Reflex is built with security-first principles to meet the needs of modern teams and enterprises."
71+
}
72+
}

pcweb/pages/security/security.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
"""Main security page implementation."""
2+
3+
import reflex as rx
4+
from pcweb.templates.mainpage import mainpage
5+
from .views import security_title, security_grid, features_table_section
6+
7+
8+
@mainpage(path="/security", title="Security - Reflex")
9+
def security():
10+
"""Main security page with modular sections."""
11+
return rx.box(
12+
rx.box(
13+
security_title(),
14+
security_grid(),
15+
features_table_section(),
16+
class_name="flex flex-col relative justify-center items-center w-full",
17+
),
18+
class_name="flex flex-col w-full",
19+
)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
"""Views package initialization."""
2+
3+
from .header import security_title
4+
from .grid import security_grid
5+
from .features_table import features_table_section
6+
7+
__all__ = [
8+
"security_title",
9+
"security_grid",
10+
"features_table_section"
11+
]
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
"""Features table section for security page."""
2+
3+
import reflex as rx
4+
from pcweb.pages.pricing.table import (
5+
create_feature_table_header,
6+
create_feature_row,
7+
create_table_body,
8+
TABLE_STYLE
9+
)
10+
from ..data import SECURITY_FEATURES, PAGE_CONTENT
11+
12+
13+
def security_table_header() -> rx.Component:
14+
"""Header section for the security features table."""
15+
table_content = PAGE_CONTENT["table"]
16+
17+
return rx.box(
18+
rx.el.h3(
19+
table_content["title"],
20+
class_name="text-slate-12 text-3xl font-semibold text-center",
21+
),
22+
rx.el.p(
23+
table_content["description"],
24+
class_name="text-slate-9 text-xl font-medium text-center mt-4",
25+
),
26+
class_name="flex items-center justify-between text-slate-11 flex-col py-[5rem] max-w-[64.19rem] mx-auto w-full px-6 lg:border-x border-slate-3",
27+
)
28+
29+
30+
def create_security_table_section(category: str, features: list) -> list:
31+
"""Create a table section with header and body for a security category."""
32+
return [
33+
rx.table.header(
34+
create_feature_table_header(category),
35+
class_name="relative",
36+
),
37+
create_table_body(
38+
*[
39+
create_feature_row(feature, description)
40+
for feature, description in features
41+
],
42+
),
43+
]
44+
45+
46+
def security_features_table() -> rx.Component:
47+
"""Complete security features table with all categories."""
48+
table_sections = []
49+
50+
# Generate all table sections dynamically
51+
for category, features in SECURITY_FEATURES.items():
52+
table_sections.extend(create_security_table_section(category, features))
53+
54+
return rx.table.root(
55+
rx.el.style(TABLE_STYLE),
56+
*table_sections,
57+
class_name="w-full overflow-x-auto max-w-[69.125rem] -mt-[2rem]",
58+
)
59+
60+
61+
def features_table_section() -> rx.Component:
62+
"""Complete features table section with header and table."""
63+
return rx.box(
64+
security_table_header(),
65+
security_features_table(),
66+
class_name="flex-col w-full max-w-[69.125rem] desktop-only",
67+
)

pcweb/pages/security/views/grid.py

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
"""Grid section for security page featuring trust services criteria."""
2+
3+
import reflex as rx
4+
from pcweb.components.icons import get_icon
5+
from ..data import PAGE_CONTENT, TRUST_SERVICES_CRITERIA
6+
7+
8+
def security_card(
9+
title: str,
10+
description: str,
11+
icon: str,
12+
cols: str = "1",
13+
class_name: str = "",
14+
) -> rx.Component:
15+
"""Individual security feature card component."""
16+
return rx.box(
17+
rx.box(
18+
_card_header(title, icon),
19+
_card_description(description),
20+
class_name="flex flex-col gap-[0.875rem]",
21+
),
22+
class_name=f"overflow-hidden p-8 w-full {class_name} lg:col-span-{cols} h-[13rem] lg:h-[11rem] border-slate-3",
23+
)
24+
25+
26+
def _card_header(title: str, icon: str) -> rx.Component:
27+
"""Card header with icon and title."""
28+
return rx.box(
29+
get_icon(icon, class_name="!text-slate-9"),
30+
rx.el.h3(title, class_name="text-slate-12 text-base font-semibold"),
31+
class_name="flex flex-row items-center gap-2",
32+
)
33+
34+
35+
def _card_description(description: str) -> rx.Component:
36+
"""Card description text."""
37+
return rx.el.p(
38+
description, class_name="text-slate-9 font-medium text-sm text-start"
39+
)
40+
41+
42+
def outcomes_showcase() -> rx.Component:
43+
"""Central outcomes showcase component with prominent display."""
44+
showcase = PAGE_CONTENT["showcase"]
45+
46+
return rx.box(
47+
rx.box(
48+
rx.box(
49+
rx.el.h2(
50+
showcase["title"],
51+
class_name="text-slate-12 text-lg lg:text-2xl font-semibold text-center",
52+
),
53+
rx.el.h3(
54+
showcase["subtitle"],
55+
class_name="text-slate-9 text-md lg:text-xl font-semibold text-center",
56+
),
57+
class_name="flex flex-col gap-2 p-10 items-center justify-center",
58+
),
59+
rx.box(
60+
rx.box(
61+
*[
62+
rx.image(
63+
src=logo["src"],
64+
alt=logo["alt"],
65+
class_name="h-24 w-auto"
66+
)
67+
for logo in showcase["logos"]
68+
],
69+
class_name="flex flex-row gap-10 items-center justify-center",
70+
),
71+
class_name="p-10 flex items-center justify-center",
72+
),
73+
class_name="flex flex-col justify-center items-center h-full",
74+
),
75+
class_name="h-full w-full flex flex-col justify-center items-center relative overflow-hidden lg:row-span-3 lg:col-span-1 lg:border-l lg:border-r border-slate-3 p-8 lg:p-1",
76+
)
77+
78+
79+
def security_grid() -> rx.Component:
80+
"""Main security features grid component with responsive layout."""
81+
criteria = TRUST_SERVICES_CRITERIA
82+
83+
# Mobile layout - simple single column stack
84+
mobile_layout = rx.box(
85+
*[security_card(**criterion) for criterion in criteria],
86+
class_name="lg:hidden flex flex-col divide-y divide-slate-3 border border-slate-3"
87+
)
88+
89+
# Desktop layout - complex grid with showcase
90+
desktop_layout = rx.box(
91+
# Last card (spans 2 columns) -> moved to top
92+
security_card(
93+
**criteria[4],
94+
cols="2",
95+
class_name="lg:col-span-2"
96+
),
97+
98+
# Center showcase (spans 3 rows, 1 column)
99+
outcomes_showcase(),
100+
101+
# First 2 cards
102+
*[security_card(**criterion) for criterion in criteria[:2]],
103+
104+
# Next 2 cards
105+
*[security_card(**criterion) for criterion in criteria[2:4]],
106+
107+
class_name=(
108+
"hidden lg:grid lg:grid-cols-3 lg:grid-rows-3 "
109+
"w-full border border-slate-3"
110+
)
111+
)
112+
113+
return rx.box(
114+
mobile_layout,
115+
desktop_layout,
116+
class_name="flex flex-row max-w-[64.19rem] justify-center w-full",
117+
)
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
"""Header section for security page."""
2+
3+
import reflex as rx
4+
from pcweb.components.hosting_banner import HostingBannerState
5+
from ..data import PAGE_CONTENT
6+
7+
8+
def security_title() -> rx.Component:
9+
"""Main title section for security page."""
10+
content = PAGE_CONTENT
11+
12+
return rx.el.section(
13+
rx.el.h1(
14+
content["title"],
15+
class_name="max-w-full inline-block bg-clip-text bg-gradient-to-r from-slate-12 to-slate-11 w-full text-4xl lg:text-5xl text-center text-transparent text-balance mx-auto break-words font-semibold",
16+
),
17+
rx.el.h2(
18+
content["subtitle"],
19+
class_name="max-w-full w-full font-large text-center text-slate-11 -mt-2 font-normal text-[1.25rem] mx-auto text-balance word-wrap break-words md:whitespace-pre",
20+
),
21+
class_name="flex flex-col justify-center items-center gap-4 mx-auto w-full max-w-[64.19rem] lg:border-x border-slate-3 pb-4 lg:pb-[7.875rem]"
22+
+ rx.cond(
23+
HostingBannerState.show_banner,
24+
" lg:pt-[15.2rem] pt-[8rem]",
25+
" lg:pt-[13.2rem] pt-[6rem]",
26+
),
27+
)

0 commit comments

Comments
 (0)