create-astram-app 0.1.2 → 0.2.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 (101) hide show
  1. package/dist/add-frontend.js +107 -0
  2. package/dist/add-frontend.js.map +1 -0
  3. package/dist/index.js +132 -33
  4. package/dist/index.js.map +1 -1
  5. package/package.json +3 -2
  6. package/template/CLAUDE.md +51 -0
  7. package/template/README.md +43 -44
  8. package/template/_gitignore +6 -0
  9. package/template/frontend/FRONTEND.md +92 -0
  10. package/template/frontend/README.md +16 -0
  11. package/template/frontend/_env.example +6 -0
  12. package/template/frontend/_gitignore +9 -0
  13. package/template/frontend/eslint.config.js +71 -0
  14. package/template/frontend/index.html +13 -0
  15. package/template/frontend/package.json +52 -0
  16. package/template/frontend/public/astram-logo-full.png +0 -0
  17. package/template/frontend/public/astram-logo-white.png +0 -0
  18. package/template/frontend/public/favicon.png +0 -0
  19. package/template/frontend/src/App.jsx +167 -0
  20. package/template/frontend/src/auth/AuthContext.jsx +338 -0
  21. package/template/frontend/src/components/ConfirmDialog.jsx +92 -0
  22. package/template/frontend/src/components/EntityFormModal.jsx +154 -0
  23. package/template/frontend/src/components/EntityList.jsx +480 -0
  24. package/template/frontend/src/components/PageHeader.jsx +54 -0
  25. package/template/frontend/src/components/access/CollapsibleGroup.jsx +34 -0
  26. package/template/frontend/src/components/ui/alert-dialog.tsx +175 -0
  27. package/template/frontend/src/components/ui/alert.tsx +83 -0
  28. package/template/frontend/src/components/ui/avatar.tsx +51 -0
  29. package/template/frontend/src/components/ui/badge.tsx +56 -0
  30. package/template/frontend/src/components/ui/button.tsx +67 -0
  31. package/template/frontend/src/components/ui/card.tsx +92 -0
  32. package/template/frontend/src/components/ui/checkbox.tsx +30 -0
  33. package/template/frontend/src/components/ui/date-field.tsx +47 -0
  34. package/template/frontend/src/components/ui/dialog.tsx +214 -0
  35. package/template/frontend/src/components/ui/dropdown-menu.tsx +255 -0
  36. package/template/frontend/src/components/ui/input-otp.tsx +81 -0
  37. package/template/frontend/src/components/ui/input.tsx +21 -0
  38. package/template/frontend/src/components/ui/label.tsx +46 -0
  39. package/template/frontend/src/components/ui/searchable-select.tsx +459 -0
  40. package/template/frontend/src/components/ui/select.tsx +199 -0
  41. package/template/frontend/src/components/ui/separator.tsx +26 -0
  42. package/template/frontend/src/components/ui/sheet.tsx +139 -0
  43. package/template/frontend/src/components/ui/skeleton.tsx +13 -0
  44. package/template/frontend/src/components/ui/sonner.tsx +23 -0
  45. package/template/frontend/src/components/ui/table.tsx +181 -0
  46. package/template/frontend/src/components/ui/tooltip.tsx +59 -0
  47. package/template/frontend/src/config/branding.js +80 -0
  48. package/template/frontend/src/hooks/useMobile.tsx +21 -0
  49. package/template/frontend/src/index.css +265 -0
  50. package/template/frontend/src/lib/utils.js +7 -0
  51. package/template/frontend/src/main.jsx +27 -0
  52. package/template/frontend/src/pages/Dashboard.jsx +127 -0
  53. package/template/frontend/src/pages/ForgotPassword.jsx +104 -0
  54. package/template/frontend/src/pages/Login.jsx +393 -0
  55. package/template/frontend/src/pages/ResetPassword.jsx +159 -0
  56. package/template/frontend/src/pages/access/AccessForm.jsx +416 -0
  57. package/template/frontend/src/pages/access/AccessPage.jsx +282 -0
  58. package/template/frontend/src/pages/access/RoleActionsMenu.jsx +42 -0
  59. package/template/frontend/src/pages/account/AccountLayout.jsx +229 -0
  60. package/template/frontend/src/pages/account/ChangePasswordPage.jsx +235 -0
  61. package/template/frontend/src/pages/account/ProfilePage.jsx +122 -0
  62. package/template/frontend/src/pages/account/ReenrollPage.jsx +98 -0
  63. package/template/frontend/src/pages/account/TwoFactorPage.jsx +833 -0
  64. package/template/frontend/src/pages/audit/AuditPage.jsx +268 -0
  65. package/template/frontend/src/pages/companies/CompaniesPage.jsx +232 -0
  66. package/template/frontend/src/pages/companies/CompanyForm.jsx +127 -0
  67. package/template/frontend/src/pages/roles/RoleForm.jsx +99 -0
  68. package/template/frontend/src/pages/roles/RolesPage.jsx +207 -0
  69. package/template/frontend/src/pages/users/AssignmentsEditor.jsx +193 -0
  70. package/template/frontend/src/pages/users/MembershipCard.jsx +303 -0
  71. package/template/frontend/src/pages/users/PostingRow.jsx +264 -0
  72. package/template/frontend/src/pages/users/UserForm.jsx +167 -0
  73. package/template/frontend/src/pages/users/UsersPage.jsx +232 -0
  74. package/template/frontend/src/platform/httpClient.js +125 -0
  75. package/template/frontend/src/platform/returnPathStore.js +43 -0
  76. package/template/frontend/src/platform/sessionStore.js +29 -0
  77. package/template/frontend/src/platform/shieldTransport.js +172 -0
  78. package/template/frontend/src/platform/shieldTransport.test.mjs +245 -0
  79. package/template/frontend/src/shell/AppShell.jsx +237 -0
  80. package/template/frontend/src/shell/Sidebar.jsx +257 -0
  81. package/template/frontend/src/shell/nav.js +90 -0
  82. package/template/frontend/src/theme/ThemeProvider.jsx +14 -0
  83. package/template/frontend/src/theme/ThemeToggle.jsx +44 -0
  84. package/template/frontend/tsconfig.json +22 -0
  85. package/template/frontend/vite.config.js +30 -0
  86. package/template/server/_env.example +45 -0
  87. package/template/server/eslint.config.js +95 -0
  88. package/template/server/package.json +49 -0
  89. package/template/server/scripts/dev.mjs +51 -0
  90. package/template/server/scripts/sync-astram-guide.mjs +63 -0
  91. package/template/_env.example +0 -33
  92. package/template/package.json +0 -37
  93. /package/template/{src → server/src}/app.module.ts +0 -0
  94. /package/template/{src → server/src}/features/_gitkeep +0 -0
  95. /package/template/{src → server/src}/health/demo.controller.ts +0 -0
  96. /package/template/{src → server/src}/health/health.controller.ts +0 -0
  97. /package/template/{src → server/src}/main.ts +0 -0
  98. /package/template/{test → server/test}/enforcement.e2e.spec.ts +0 -0
  99. /package/template/{tsconfig.build.json → server/tsconfig.build.json} +0 -0
  100. /package/template/{tsconfig.json → server/tsconfig.json} +0 -0
  101. /package/template/{vitest.config.ts → server/vitest.config.ts} +0 -0
@@ -0,0 +1,98 @@
1
+ /**
2
+ * ReenrollPage — the FORCED re-enroll screen shown after a recovery-code login.
3
+ *
4
+ * Signing in with a recovery code marks the session `mustReenroll` (server-side, §4):
5
+ * every non-allowlisted route returns 403 `reenrollment_required`, so the app pins the
6
+ * user here (App.jsx's ReenrollGate) until they re-secure the account by confirming a
7
+ * fresh authenticator device. The device-add + recovery-codes UI is REUSED verbatim
8
+ * from <TwoFactorPage/> (single source of truth for the enroll flow); this screen only
9
+ * adds the framing + the "you're done" transition.
10
+ *
11
+ * When a device confirm succeeds, the server clears the gate on the SAME token (§4.3) —
12
+ * the next request is unrestricted. We clear the local re-enroll flag at that moment
13
+ * (so the user is no longer bounced) while keeping them on-screen to save any one-time
14
+ * recovery codes, then offer an explicit "Continue" back into the app.
15
+ */
16
+ import { useState } from 'react';
17
+ import { useNavigate } from 'react-router-dom';
18
+ import { ArrowRight, LogOut, ShieldAlert, ShieldCheck } from 'lucide-react';
19
+ import { useAuth } from '@/auth/AuthContext';
20
+ import { Button } from '@/components/ui/button';
21
+ import TwoFactorPage from './TwoFactorPage';
22
+
23
+ export default function ReenrollPage() {
24
+ const { clearReenroll, logout } = useAuth();
25
+ const navigate = useNavigate();
26
+ const [secured, setSecured] = useState(false);
27
+
28
+ // A device confirm succeeded → the server has already lifted the restriction on this
29
+ // token; release the UI gate so the user can leave once they've saved their codes.
30
+ const onDeviceConfirmed = () => {
31
+ setSecured(true);
32
+ clearReenroll();
33
+ };
34
+
35
+ const onSignOut = async () => {
36
+ await logout();
37
+ navigate('/login', { replace: true });
38
+ };
39
+
40
+ return (
41
+ <div className="grid-bg relative min-h-screen bg-background px-4 py-10">
42
+ <div className="mx-auto w-full max-w-3xl space-y-6">
43
+ {/* Framing banner — states WHY the user is here and what unlocks the app. */}
44
+ <div
45
+ className={
46
+ secured
47
+ ? 'flex items-start gap-3 rounded-xl border border-primary/30 bg-primary/5 px-4 py-3.5'
48
+ : 'flex items-start gap-3 rounded-xl border border-[var(--warn)]/40 bg-[var(--warn)]/10 px-4 py-3.5'
49
+ }
50
+ >
51
+ {secured ? (
52
+ <ShieldCheck className="mt-0.5 size-5 shrink-0 text-primary" />
53
+ ) : (
54
+ <ShieldAlert className="mt-0.5 size-5 shrink-0 text-[var(--warn)]" />
55
+ )}
56
+ <div className="min-w-0">
57
+ <p className="text-sm font-semibold text-foreground">
58
+ {secured
59
+ ? 'Your account is secured again'
60
+ : 'Finish securing your account'}
61
+ </p>
62
+ <p className="mt-0.5 text-sm text-muted-foreground">
63
+ {secured
64
+ ? 'A new authenticator device is active. Save any recovery codes shown below, then continue.'
65
+ : 'You signed in with a recovery code. Add a new authenticator device below to re-secure your account — the rest of the app stays locked until you do.'}
66
+ </p>
67
+ </div>
68
+ </div>
69
+
70
+ {/* The re-enroll work — the exact device-add + regenerate-codes flow from the
71
+ account 2FA page, reused as-is. onDeviceConfirmed lifts the gate on success.
72
+ reenrollMode hides Rename/Remove on existing devices (those routes aren't on
73
+ the server's re-enroll allowlist → they'd only 403 here). */}
74
+ <TwoFactorPage onDeviceConfirmed={onDeviceConfirmed} reenrollMode />
75
+
76
+ {!secured && (
77
+ <p className="text-center text-xs text-muted-foreground">
78
+ You can rename or remove existing devices from your account settings once your account is
79
+ secured.
80
+ </p>
81
+ )}
82
+
83
+ <div className="flex flex-wrap items-center justify-between gap-3">
84
+ <Button type="button" variant="ghost" onClick={onSignOut}>
85
+ <LogOut className="size-4" />
86
+ Sign out instead
87
+ </Button>
88
+ {secured && (
89
+ <Button type="button" onClick={() => navigate('/dashboard', { replace: true })}>
90
+ Continue to the app
91
+ <ArrowRight className="size-4" />
92
+ </Button>
93
+ )}
94
+ </div>
95
+ </div>
96
+ </div>
97
+ );
98
+ }