@codaijs/keel 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/dist/__tests__/cli.test.d.ts +2 -0
  2. package/dist/__tests__/cli.test.d.ts.map +1 -0
  3. package/dist/__tests__/cli.test.js +173 -0
  4. package/dist/__tests__/cli.test.js.map +1 -0
  5. package/dist/__tests__/registry.test.d.ts +2 -0
  6. package/dist/__tests__/registry.test.d.ts.map +1 -0
  7. package/dist/__tests__/registry.test.js +86 -0
  8. package/dist/__tests__/registry.test.js.map +1 -0
  9. package/dist/__tests__/sail-installer.test.d.ts +2 -0
  10. package/dist/__tests__/sail-installer.test.d.ts.map +1 -0
  11. package/dist/__tests__/sail-installer.test.js +158 -0
  12. package/dist/__tests__/sail-installer.test.js.map +1 -0
  13. package/dist/create-runner.d.ts +11 -0
  14. package/dist/create-runner.d.ts.map +1 -0
  15. package/dist/create-runner.js +63 -0
  16. package/dist/create-runner.js.map +1 -0
  17. package/dist/create.d.ts +10 -0
  18. package/dist/create.d.ts.map +1 -0
  19. package/dist/create.js +15 -0
  20. package/dist/create.js.map +1 -0
  21. package/dist/manage.d.ts +24 -0
  22. package/dist/manage.d.ts.map +1 -0
  23. package/dist/manage.js +1461 -0
  24. package/dist/manage.js.map +1 -0
  25. package/dist/prompts.d.ts +36 -0
  26. package/dist/prompts.d.ts.map +1 -0
  27. package/dist/prompts.js +208 -0
  28. package/dist/prompts.js.map +1 -0
  29. package/dist/sail-installer.d.ts +37 -0
  30. package/dist/sail-installer.d.ts.map +1 -0
  31. package/dist/sail-installer.js +935 -0
  32. package/dist/sail-installer.js.map +1 -0
  33. package/dist/scaffold.d.ts +10 -0
  34. package/dist/scaffold.d.ts.map +1 -0
  35. package/dist/scaffold.js +297 -0
  36. package/dist/scaffold.js.map +1 -0
  37. package/package.json +57 -0
  38. package/sails/_template/addon.json +20 -0
  39. package/sails/_template/install.ts +402 -0
  40. package/sails/admin-dashboard/README.md +117 -0
  41. package/sails/admin-dashboard/addon.json +28 -0
  42. package/sails/admin-dashboard/files/backend/middleware/admin.ts +34 -0
  43. package/sails/admin-dashboard/files/backend/routes/admin.ts +243 -0
  44. package/sails/admin-dashboard/files/frontend/components/admin/StatsCard.tsx +40 -0
  45. package/sails/admin-dashboard/files/frontend/components/admin/UsersTable.tsx +240 -0
  46. package/sails/admin-dashboard/files/frontend/hooks/useAdmin.ts +149 -0
  47. package/sails/admin-dashboard/files/frontend/pages/admin/Dashboard.tsx +173 -0
  48. package/sails/admin-dashboard/files/frontend/pages/admin/UserDetail.tsx +203 -0
  49. package/sails/admin-dashboard/install.ts +305 -0
  50. package/sails/analytics/README.md +178 -0
  51. package/sails/analytics/addon.json +27 -0
  52. package/sails/analytics/files/frontend/components/AnalyticsProvider.tsx +58 -0
  53. package/sails/analytics/files/frontend/hooks/useAnalytics.ts +64 -0
  54. package/sails/analytics/files/frontend/lib/analytics.ts +103 -0
  55. package/sails/analytics/install.ts +297 -0
  56. package/sails/file-uploads/README.md +191 -0
  57. package/sails/file-uploads/addon.json +30 -0
  58. package/sails/file-uploads/files/backend/routes/files.ts +198 -0
  59. package/sails/file-uploads/files/backend/schema/files.ts +36 -0
  60. package/sails/file-uploads/files/backend/services/file-storage.ts +128 -0
  61. package/sails/file-uploads/files/frontend/components/FileList.tsx +248 -0
  62. package/sails/file-uploads/files/frontend/components/FileUploadButton.tsx +147 -0
  63. package/sails/file-uploads/files/frontend/hooks/useFileUpload.ts +106 -0
  64. package/sails/file-uploads/files/frontend/hooks/useFiles.ts +118 -0
  65. package/sails/file-uploads/files/frontend/pages/Files.tsx +37 -0
  66. package/sails/file-uploads/install.ts +466 -0
  67. package/sails/gdpr/README.md +174 -0
  68. package/sails/gdpr/addon.json +27 -0
  69. package/sails/gdpr/files/backend/routes/gdpr.ts +140 -0
  70. package/sails/gdpr/files/backend/services/gdpr.ts +293 -0
  71. package/sails/gdpr/files/frontend/components/auth/ConsentCheckboxes.tsx +97 -0
  72. package/sails/gdpr/files/frontend/components/gdpr/AccountDeletionRequest.tsx +192 -0
  73. package/sails/gdpr/files/frontend/components/gdpr/DataExportButton.tsx +75 -0
  74. package/sails/gdpr/files/frontend/pages/PrivacyPolicy.tsx +186 -0
  75. package/sails/gdpr/install.ts +756 -0
  76. package/sails/google-oauth/README.md +121 -0
  77. package/sails/google-oauth/addon.json +22 -0
  78. package/sails/google-oauth/files/GoogleButton.tsx +50 -0
  79. package/sails/google-oauth/install.ts +252 -0
  80. package/sails/i18n/README.md +193 -0
  81. package/sails/i18n/addon.json +30 -0
  82. package/sails/i18n/files/frontend/components/LanguageSwitcher.tsx +108 -0
  83. package/sails/i18n/files/frontend/hooks/useLanguage.ts +31 -0
  84. package/sails/i18n/files/frontend/lib/i18n.ts +32 -0
  85. package/sails/i18n/files/frontend/locales/de/common.json +44 -0
  86. package/sails/i18n/files/frontend/locales/en/common.json +44 -0
  87. package/sails/i18n/install.ts +407 -0
  88. package/sails/push-notifications/README.md +163 -0
  89. package/sails/push-notifications/addon.json +31 -0
  90. package/sails/push-notifications/files/backend/routes/notifications.ts +153 -0
  91. package/sails/push-notifications/files/backend/schema/notifications.ts +31 -0
  92. package/sails/push-notifications/files/backend/services/notifications.ts +117 -0
  93. package/sails/push-notifications/files/frontend/components/PushNotificationInit.tsx +12 -0
  94. package/sails/push-notifications/files/frontend/hooks/usePushNotifications.ts +154 -0
  95. package/sails/push-notifications/install.ts +384 -0
  96. package/sails/r2-storage/README.md +101 -0
  97. package/sails/r2-storage/addon.json +29 -0
  98. package/sails/r2-storage/files/backend/services/storage.ts +71 -0
  99. package/sails/r2-storage/files/frontend/components/ProfilePictureUpload.tsx +167 -0
  100. package/sails/r2-storage/install.ts +412 -0
  101. package/sails/rate-limiting/README.md +145 -0
  102. package/sails/rate-limiting/addon.json +20 -0
  103. package/sails/rate-limiting/files/backend/middleware/rate-limit-store.ts +104 -0
  104. package/sails/rate-limiting/files/backend/middleware/rate-limit.ts +137 -0
  105. package/sails/rate-limiting/install.ts +300 -0
  106. package/sails/registry.json +107 -0
  107. package/sails/stripe/README.md +214 -0
  108. package/sails/stripe/addon.json +24 -0
  109. package/sails/stripe/files/backend/routes/stripe.ts +154 -0
  110. package/sails/stripe/files/backend/schema/stripe.ts +74 -0
  111. package/sails/stripe/files/backend/services/stripe.ts +224 -0
  112. package/sails/stripe/files/frontend/components/SubscriptionStatus.tsx +135 -0
  113. package/sails/stripe/files/frontend/hooks/useSubscription.ts +86 -0
  114. package/sails/stripe/files/frontend/pages/Checkout.tsx +116 -0
  115. package/sails/stripe/files/frontend/pages/Pricing.tsx +226 -0
  116. package/sails/stripe/install.ts +378 -0
@@ -0,0 +1,192 @@
1
+ import { useState, useEffect } from "react";
2
+ import { apiGet, apiPost, apiDelete } from "@/lib/api";
3
+
4
+ interface DeletionStatus {
5
+ pending: boolean;
6
+ scheduledAt?: string;
7
+ }
8
+
9
+ export default function AccountDeletionRequest() {
10
+ const [deletionStatus, setDeletionStatus] = useState<DeletionStatus>({
11
+ pending: false,
12
+ });
13
+ const [reason, setReason] = useState("");
14
+ const [showConfirm, setShowConfirm] = useState(false);
15
+ const [isLoading, setIsLoading] = useState(false);
16
+ const [error, setError] = useState("");
17
+
18
+ useEffect(() => {
19
+ async function checkStatus() {
20
+ try {
21
+ const status = await apiGet<DeletionStatus>(
22
+ "/api/gdpr/deletion-status",
23
+ );
24
+ setDeletionStatus(status);
25
+ } catch {
26
+ // No pending deletion
27
+ }
28
+ }
29
+ checkStatus();
30
+ }, []);
31
+
32
+ const handleRequestDeletion = async () => {
33
+ setIsLoading(true);
34
+ setError("");
35
+
36
+ try {
37
+ const status = await apiPost<DeletionStatus>("/api/gdpr/delete-account", {
38
+ reason: reason || undefined,
39
+ });
40
+ setDeletionStatus(status);
41
+ setShowConfirm(false);
42
+ } catch (err) {
43
+ setError(
44
+ err instanceof Error ? err.message : "Failed to request deletion.",
45
+ );
46
+ } finally {
47
+ setIsLoading(false);
48
+ }
49
+ };
50
+
51
+ const handleCancelDeletion = async () => {
52
+ setIsLoading(true);
53
+ setError("");
54
+
55
+ try {
56
+ await apiDelete("/api/gdpr/delete-account");
57
+ setDeletionStatus({ pending: false });
58
+ } catch (err) {
59
+ setError(
60
+ err instanceof Error
61
+ ? err.message
62
+ : "Failed to cancel deletion request.",
63
+ );
64
+ } finally {
65
+ setIsLoading(false);
66
+ }
67
+ };
68
+
69
+ if (deletionStatus.pending) {
70
+ const scheduledDate = deletionStatus.scheduledAt
71
+ ? new Date(deletionStatus.scheduledAt).toLocaleDateString("en-US", {
72
+ year: "numeric",
73
+ month: "long",
74
+ day: "numeric",
75
+ })
76
+ : "30 days from now";
77
+
78
+ return (
79
+ <div>
80
+ <div className="rounded-lg border border-amber-500/30 bg-amber-500/10 p-4">
81
+ <div className="flex items-start gap-3">
82
+ <svg
83
+ className="mt-0.5 h-5 w-5 shrink-0 text-amber-400"
84
+ fill="none"
85
+ viewBox="0 0 24 24"
86
+ stroke="currentColor"
87
+ >
88
+ <path
89
+ strokeLinecap="round"
90
+ strokeLinejoin="round"
91
+ strokeWidth={2}
92
+ d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z"
93
+ />
94
+ </svg>
95
+ <div>
96
+ <p className="text-sm font-medium text-amber-400">
97
+ Account deletion scheduled
98
+ </p>
99
+ <p className="mt-1 text-xs text-amber-400/80">
100
+ Your account is scheduled for deletion on{" "}
101
+ <span className="font-medium">{scheduledDate}</span>. You can
102
+ cancel this request before that date.
103
+ </p>
104
+ </div>
105
+ </div>
106
+ <button
107
+ onClick={handleCancelDeletion}
108
+ disabled={isLoading}
109
+ className="mt-3 rounded-lg border border-amber-500/30 px-4 py-2 text-sm font-medium text-amber-400 transition-colors hover:bg-amber-500/10 disabled:opacity-50"
110
+ >
111
+ {isLoading ? "Cancelling..." : "Cancel deletion"}
112
+ </button>
113
+ </div>
114
+ {error && <p className="mt-2 text-xs text-red-400">{error}</p>}
115
+ </div>
116
+ );
117
+ }
118
+
119
+ return (
120
+ <div>
121
+ {!showConfirm ? (
122
+ <button
123
+ onClick={() => setShowConfirm(true)}
124
+ className="inline-flex items-center rounded-lg text-sm font-medium text-red-400 transition-colors hover:bg-red-500/10 px-4 py-2"
125
+ >
126
+ <svg
127
+ className="mr-2 h-4 w-4"
128
+ fill="none"
129
+ viewBox="0 0 24 24"
130
+ stroke="currentColor"
131
+ >
132
+ <path
133
+ strokeLinecap="round"
134
+ strokeLinejoin="round"
135
+ strokeWidth={2}
136
+ d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16"
137
+ />
138
+ </svg>
139
+ Delete my account
140
+ </button>
141
+ ) : (
142
+ <div className="rounded-lg border border-red-500/30 bg-red-500/10 p-4">
143
+ <h4 className="text-sm font-medium text-red-400">
144
+ Are you sure you want to delete your account?
145
+ </h4>
146
+ <p className="mt-1 text-xs text-red-400/80">
147
+ This action will schedule your account for permanent deletion. You
148
+ will have a 30-day grace period to cancel the request. After that,
149
+ all your data will be permanently removed.
150
+ </p>
151
+
152
+ <div className="mt-3">
153
+ <label
154
+ htmlFor="deletionReason"
155
+ className="mb-1.5 block text-xs font-medium text-red-400"
156
+ >
157
+ Reason for leaving (optional)
158
+ </label>
159
+ <textarea
160
+ id="deletionReason"
161
+ value={reason}
162
+ onChange={(e) => setReason(e.target.value)}
163
+ rows={2}
164
+ placeholder="We'd appreciate knowing why you're leaving..."
165
+ className="w-full rounded-lg border border-keel-gray-800 bg-keel-gray-900 px-3 py-2 text-sm text-white placeholder-keel-gray-400 focus:border-red-400 focus:outline-none focus:ring-2 focus:ring-red-400/20"
166
+ />
167
+ </div>
168
+
169
+ <div className="mt-3 flex gap-3">
170
+ <button
171
+ onClick={handleRequestDeletion}
172
+ disabled={isLoading}
173
+ className="rounded-lg bg-red-600 px-4 py-2 text-sm font-medium text-white transition-colors hover:bg-red-700 disabled:opacity-50"
174
+ >
175
+ {isLoading ? "Processing..." : "Yes, delete my account"}
176
+ </button>
177
+ <button
178
+ onClick={() => {
179
+ setShowConfirm(false);
180
+ setReason("");
181
+ }}
182
+ className="rounded-lg border border-keel-gray-800 px-4 py-2 text-sm font-medium text-keel-gray-100 transition-colors hover:border-keel-gray-400"
183
+ >
184
+ Cancel
185
+ </button>
186
+ </div>
187
+ </div>
188
+ )}
189
+ {error && <p className="mt-2 text-xs text-red-400">{error}</p>}
190
+ </div>
191
+ );
192
+ }
@@ -0,0 +1,75 @@
1
+ import { useState } from "react";
2
+
3
+ export default function DataExportButton() {
4
+ const [isLoading, setIsLoading] = useState(false);
5
+ const [error, setError] = useState("");
6
+
7
+ const handleExport = async () => {
8
+ setIsLoading(true);
9
+ setError("");
10
+
11
+ try {
12
+ const response = await fetch("/api/gdpr/export", {
13
+ credentials: "include",
14
+ });
15
+
16
+ if (!response.ok) {
17
+ throw new Error("Failed to export data.");
18
+ }
19
+
20
+ const data = await response.json();
21
+ const blob = new Blob([JSON.stringify(data, null, 2)], {
22
+ type: "application/json",
23
+ });
24
+ const url = URL.createObjectURL(blob);
25
+ const link = document.createElement("a");
26
+ link.href = url;
27
+ link.download = `keel-data-export-${new Date().toISOString().slice(0, 10)}.json`;
28
+ document.body.appendChild(link);
29
+ link.click();
30
+ document.body.removeChild(link);
31
+ URL.revokeObjectURL(url);
32
+ } catch (err) {
33
+ setError(
34
+ err instanceof Error ? err.message : "Failed to export data.",
35
+ );
36
+ } finally {
37
+ setIsLoading(false);
38
+ }
39
+ };
40
+
41
+ return (
42
+ <div>
43
+ <button
44
+ onClick={handleExport}
45
+ disabled={isLoading}
46
+ className="inline-flex items-center rounded-lg border border-keel-gray-800 px-4 py-2 text-sm font-medium text-keel-gray-100 transition-colors hover:border-keel-gray-400 disabled:opacity-50"
47
+ >
48
+ {isLoading ? (
49
+ <>
50
+ <div className="mr-2 h-4 w-4 animate-spin rounded-full border-2 border-keel-gray-800 border-t-keel-blue" />
51
+ Exporting...
52
+ </>
53
+ ) : (
54
+ <>
55
+ <svg
56
+ className="mr-2 h-4 w-4"
57
+ fill="none"
58
+ viewBox="0 0 24 24"
59
+ stroke="currentColor"
60
+ >
61
+ <path
62
+ strokeLinecap="round"
63
+ strokeLinejoin="round"
64
+ strokeWidth={2}
65
+ d="M12 10v6m0 0l-3-3m3 3l3-3m2 8H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"
66
+ />
67
+ </svg>
68
+ Export my data
69
+ </>
70
+ )}
71
+ </button>
72
+ {error && <p className="mt-2 text-xs text-red-400">{error}</p>}
73
+ </div>
74
+ );
75
+ }
@@ -0,0 +1,186 @@
1
+ export default function PrivacyPolicy() {
2
+ return (
3
+ <div className="mx-auto w-full max-w-3xl px-4 py-8 sm:px-6 lg:px-8">
4
+ <article className="max-w-none">
5
+ <h1 className="text-3xl font-bold text-white">Privacy Policy</h1>
6
+ <p className="text-sm text-keel-gray-400">Last updated: March 18, 2026</p>
7
+
8
+ <section className="mt-8 space-y-6">
9
+ <div>
10
+ <h2 className="text-xl font-semibold text-white">
11
+ 1. What Data We Collect
12
+ </h2>
13
+ <p className="mt-2 text-sm leading-relaxed text-keel-gray-400">
14
+ We collect the following personal data when you use our service:
15
+ </p>
16
+ <ul className="mt-2 list-disc space-y-1 pl-6 text-sm text-keel-gray-400">
17
+ <li>
18
+ <strong className="text-keel-gray-100">Account information:</strong> your name, email address,
19
+ and encrypted password when you create an account.
20
+ </li>
21
+ <li>
22
+ <strong className="text-keel-gray-100">Profile data:</strong> profile picture and any
23
+ additional information you choose to provide.
24
+ </li>
25
+ <li>
26
+ <strong className="text-keel-gray-100">Usage data:</strong> information about how you interact
27
+ with our service, including pages visited, features used, and
28
+ session duration (only with your explicit consent).
29
+ </li>
30
+ <li>
31
+ <strong className="text-keel-gray-100">Technical data:</strong> IP address, browser type,
32
+ device information, and operating system for security and
33
+ service operation purposes.
34
+ </li>
35
+ </ul>
36
+ </div>
37
+
38
+ <div>
39
+ <h2 className="text-xl font-semibold text-white">
40
+ 2. Why We Collect It
41
+ </h2>
42
+ <p className="mt-2 text-sm leading-relaxed text-keel-gray-400">
43
+ We process your personal data for the following purposes:
44
+ </p>
45
+ <ul className="mt-2 list-disc space-y-1 pl-6 text-sm text-keel-gray-400">
46
+ <li>
47
+ <strong className="text-keel-gray-100">Service provision:</strong> to create and manage your
48
+ account, authenticate your identity, and provide the core
49
+ functionality of the service.
50
+ </li>
51
+ <li>
52
+ <strong className="text-keel-gray-100">Communication:</strong> to send you important service
53
+ notifications, such as email verification and password resets.
54
+ </li>
55
+ <li>
56
+ <strong className="text-keel-gray-100">Marketing:</strong> to send you product updates and
57
+ promotional content (only with your explicit consent).
58
+ </li>
59
+ <li>
60
+ <strong className="text-keel-gray-100">Analytics:</strong> to understand how the service is
61
+ used and improve it (only with your explicit consent).
62
+ </li>
63
+ <li>
64
+ <strong className="text-keel-gray-100">Security:</strong> to protect your account and detect
65
+ unauthorized access or abuse.
66
+ </li>
67
+ <li>
68
+ <strong className="text-keel-gray-100">Legal compliance:</strong> to comply with applicable
69
+ laws and regulations.
70
+ </li>
71
+ </ul>
72
+ </div>
73
+
74
+ <div>
75
+ <h2 className="text-xl font-semibold text-white">
76
+ 3. How Long We Keep It
77
+ </h2>
78
+ <p className="mt-2 text-sm leading-relaxed text-keel-gray-400">
79
+ We retain your personal data for as long as your account is
80
+ active. If you request account deletion, your data will be
81
+ permanently removed within 30 days of the scheduled deletion date.
82
+ Some data may be retained for a longer period if required by law
83
+ (e.g., financial records for tax compliance).
84
+ </p>
85
+ </div>
86
+
87
+ <div>
88
+ <h2 className="text-xl font-semibold text-white">
89
+ 4. Your Rights
90
+ </h2>
91
+ <p className="mt-2 text-sm leading-relaxed text-keel-gray-400">
92
+ Under the General Data Protection Regulation (GDPR), you have the
93
+ following rights:
94
+ </p>
95
+ <ul className="mt-2 list-disc space-y-1 pl-6 text-sm text-keel-gray-400">
96
+ <li>
97
+ <strong className="text-keel-gray-100">Right of access:</strong> you can request a copy of your
98
+ personal data at any time.
99
+ </li>
100
+ <li>
101
+ <strong className="text-keel-gray-100">Right to data portability:</strong> you can export your
102
+ data in a machine-readable format (JSON).
103
+ </li>
104
+ <li>
105
+ <strong className="text-keel-gray-100">Right to erasure:</strong> you can request the deletion
106
+ of your account and all associated data.
107
+ </li>
108
+ <li>
109
+ <strong className="text-keel-gray-100">Right to withdraw consent:</strong> you can withdraw any
110
+ optional consent (marketing, analytics) at any time through your
111
+ account settings.
112
+ </li>
113
+ <li>
114
+ <strong className="text-keel-gray-100">Right to rectification:</strong> you can update or
115
+ correct your personal data through your profile settings.
116
+ </li>
117
+ <li>
118
+ <strong className="text-keel-gray-100">Right to object:</strong> you can object to the
119
+ processing of your personal data for specific purposes.
120
+ </li>
121
+ </ul>
122
+ </div>
123
+
124
+ <div>
125
+ <h2 className="text-xl font-semibold text-white">
126
+ 5. How to Exercise Your Rights
127
+ </h2>
128
+ <p className="mt-2 text-sm leading-relaxed text-keel-gray-400">
129
+ You can exercise most of your rights directly through the
130
+ application:
131
+ </p>
132
+ <ul className="mt-2 list-disc space-y-1 pl-6 text-sm text-keel-gray-400">
133
+ <li>
134
+ <strong className="text-keel-gray-100">Data export:</strong> go to Settings &gt; Data &amp;
135
+ Privacy &gt; Export my data.
136
+ </li>
137
+ <li>
138
+ <strong className="text-keel-gray-100">Account deletion:</strong> go to Settings &gt; Data
139
+ &amp; Privacy &gt; Delete my account.
140
+ </li>
141
+ <li>
142
+ <strong className="text-keel-gray-100">Consent management:</strong> go to Settings &gt; Consent
143
+ Preferences to manage your marketing and analytics opt-ins.
144
+ </li>
145
+ <li>
146
+ <strong className="text-keel-gray-100">Profile updates:</strong> go to Profile to update your
147
+ personal information.
148
+ </li>
149
+ </ul>
150
+ <p className="mt-2 text-sm leading-relaxed text-keel-gray-400">
151
+ For any other requests, please contact us using the information
152
+ below.
153
+ </p>
154
+ </div>
155
+
156
+ <div>
157
+ <h2 className="text-xl font-semibold text-white">
158
+ 6. Data Security
159
+ </h2>
160
+ <p className="mt-2 text-sm leading-relaxed text-keel-gray-400">
161
+ We implement appropriate technical and organizational measures to
162
+ protect your personal data against unauthorized access, alteration,
163
+ disclosure, or destruction. This includes encryption of passwords,
164
+ secure HTTPS connections, and regular security audits.
165
+ </p>
166
+ </div>
167
+
168
+ <div>
169
+ <h2 className="text-xl font-semibold text-white">
170
+ 7. Contact Information
171
+ </h2>
172
+ <p className="mt-2 text-sm leading-relaxed text-keel-gray-400">
173
+ If you have any questions about this Privacy Policy or wish to
174
+ exercise your rights, please contact us at:
175
+ </p>
176
+ <p className="mt-2 text-sm text-keel-gray-400">
177
+ <strong className="text-keel-gray-100">Email:</strong> privacy@yourdomain.com
178
+ <br />
179
+ <strong className="text-keel-gray-100">Data Protection Officer:</strong> dpo@yourdomain.com
180
+ </p>
181
+ </div>
182
+ </section>
183
+ </article>
184
+ </div>
185
+ );
186
+ }