create-mithaq 0.0.0-stage → 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.
- package/LICENSE +22 -0
- package/LICENSES/openstatus-time-picker.txt +21 -0
- package/LICENSES/payload.txt +22 -0
- package/LICENSES/ponytail.txt +21 -0
- package/index.js +521 -0
- package/package.json +19 -4
- package/template/apps/asas-backoffice/components.json +25 -0
- package/template/apps/asas-backoffice/gitignore +3 -0
- package/template/apps/asas-backoffice/package.json +57 -0
- package/template/apps/asas-backoffice/public/favicon.svg +1 -0
- package/template/apps/asas-backoffice/src/api.ts +147 -0
- package/template/apps/asas-backoffice/src/auth-frame.tsx +150 -0
- package/template/apps/asas-backoffice/src/components/ui/accordion.tsx +74 -0
- package/template/apps/asas-backoffice/src/components/ui/alert-dialog.tsx +185 -0
- package/template/apps/asas-backoffice/src/components/ui/avatar.tsx +106 -0
- package/template/apps/asas-backoffice/src/components/ui/badge.tsx +48 -0
- package/template/apps/asas-backoffice/src/components/ui/breadcrumb.tsx +124 -0
- package/template/apps/asas-backoffice/src/components/ui/button-group.tsx +87 -0
- package/template/apps/asas-backoffice/src/components/ui/button.tsx +55 -0
- package/template/apps/asas-backoffice/src/components/ui/calendar.tsx +223 -0
- package/template/apps/asas-backoffice/src/components/ui/card.tsx +102 -0
- package/template/apps/asas-backoffice/src/components/ui/chart.tsx +371 -0
- package/template/apps/asas-backoffice/src/components/ui/checkbox.tsx +28 -0
- package/template/apps/asas-backoffice/src/components/ui/collapsible.tsx +19 -0
- package/template/apps/asas-backoffice/src/components/ui/combobox.tsx +308 -0
- package/template/apps/asas-backoffice/src/components/ui/dialog.tsx +158 -0
- package/template/apps/asas-backoffice/src/components/ui/direction.tsx +6 -0
- package/template/apps/asas-backoffice/src/components/ui/directional-icon.tsx +20 -0
- package/template/apps/asas-backoffice/src/components/ui/dropdown-menu.tsx +267 -0
- package/template/apps/asas-backoffice/src/components/ui/field.tsx +236 -0
- package/template/apps/asas-backoffice/src/components/ui/input-group.tsx +155 -0
- package/template/apps/asas-backoffice/src/components/ui/input-otp.tsx +84 -0
- package/template/apps/asas-backoffice/src/components/ui/input.tsx +19 -0
- package/template/apps/asas-backoffice/src/components/ui/label.tsx +19 -0
- package/template/apps/asas-backoffice/src/components/ui/popover.tsx +90 -0
- package/template/apps/asas-backoffice/src/components/ui/radio-group.tsx +37 -0
- package/template/apps/asas-backoffice/src/components/ui/resizable.tsx +47 -0
- package/template/apps/asas-backoffice/src/components/ui/scroll-area.tsx +54 -0
- package/template/apps/asas-backoffice/src/components/ui/select.tsx +204 -0
- package/template/apps/asas-backoffice/src/components/ui/separator.tsx +24 -0
- package/template/apps/asas-backoffice/src/components/ui/sheet.tsx +139 -0
- package/template/apps/asas-backoffice/src/components/ui/sidebar.tsx +714 -0
- package/template/apps/asas-backoffice/src/components/ui/skeleton.tsx +13 -0
- package/template/apps/asas-backoffice/src/components/ui/slider.tsx +55 -0
- package/template/apps/asas-backoffice/src/components/ui/spinner.tsx +10 -0
- package/template/apps/asas-backoffice/src/components/ui/switch.tsx +29 -0
- package/template/apps/asas-backoffice/src/components/ui/table.tsx +115 -0
- package/template/apps/asas-backoffice/src/components/ui/tabs.tsx +79 -0
- package/template/apps/asas-backoffice/src/components/ui/textarea.tsx +17 -0
- package/template/apps/asas-backoffice/src/components/ui/toggle-group.tsx +89 -0
- package/template/apps/asas-backoffice/src/components/ui/toggle.tsx +44 -0
- package/template/apps/asas-backoffice/src/components/ui/tooltip.tsx +63 -0
- package/template/apps/asas-backoffice/src/components.ts +35 -0
- package/template/apps/asas-backoffice/src/copy.ts +1 -0
- package/template/apps/asas-backoffice/src/first-user.ts +14 -0
- package/template/apps/asas-backoffice/src/hooks/use-mobile.ts +19 -0
- package/template/apps/asas-backoffice/src/lib/utils.ts +1 -0
- package/template/apps/asas-backoffice/src/links.ts +38 -0
- package/template/apps/asas-backoffice/src/locale-switch.tsx +28 -0
- package/template/apps/asas-backoffice/src/no-organization.tsx +5 -0
- package/template/apps/asas-backoffice/src/redirect.ts +1 -0
- package/template/apps/asas-backoffice/src/request-headers.ts +11 -0
- package/template/apps/asas-backoffice/src/routeTree.gen.ts +206 -0
- package/template/apps/asas-backoffice/src/router.tsx +18 -0
- package/template/apps/asas-backoffice/src/routes/(screens)/backoffice/files.ts +10 -0
- package/template/apps/asas-backoffice/src/routes/(screens)/backoffice/screen.json +3971 -0
- package/template/apps/asas-backoffice/src/routes/(screens)/backoffice/types.ts +163 -0
- package/template/apps/asas-backoffice/src/routes/(screens)/backoffice.$.tsx +17 -0
- package/template/apps/asas-backoffice/src/routes/(screens)/backoffice.index.tsx +10 -0
- package/template/apps/asas-backoffice/src/routes/(screens)/backoffice.tsx +13 -0
- package/template/apps/asas-backoffice/src/routes/__root.tsx +95 -0
- package/template/apps/asas-backoffice/src/routes/api/$.ts +34 -0
- package/template/apps/asas-backoffice/src/routes/auth.create-first-user.tsx +113 -0
- package/template/apps/asas-backoffice/src/routes/auth.sign-in.tsx +77 -0
- package/template/apps/asas-backoffice/src/routes/unauthorized.tsx +134 -0
- package/template/apps/asas-backoffice/src/screen-form.tsx +36 -0
- package/template/apps/asas-backoffice/src/screen-list.tsx +140 -0
- package/template/apps/asas-backoffice/src/screen-names.ts +10 -0
- package/template/apps/asas-backoffice/src/screens.tsx +888 -0
- package/template/apps/asas-backoffice/src/server.ts +30 -0
- package/template/apps/asas-backoffice/src/slide.ts +22 -0
- package/template/apps/asas-backoffice/src/start.ts +42 -0
- package/template/apps/asas-backoffice/src/styles.css +202 -0
- package/template/apps/asas-backoffice/src/theme.ts +2 -0
- package/template/apps/asas-backoffice/tsconfig.json +19 -0
- package/template/apps/asas-backoffice/vite.config.ts +32 -0
- package/template/apps/asas-tanstack/components.json +25 -0
- package/template/apps/asas-tanstack/gitignore +3 -0
- package/template/apps/asas-tanstack/package.json +58 -0
- package/template/apps/asas-tanstack/public/favicon.svg +1 -0
- package/template/apps/asas-tanstack/src/api.ts +147 -0
- package/template/apps/asas-tanstack/src/auth-frame.tsx +150 -0
- package/template/apps/asas-tanstack/src/choose-password.tsx +150 -0
- package/template/apps/asas-tanstack/src/components/ui/accordion.tsx +10 -0
- package/template/apps/asas-tanstack/src/components/ui/alert-dialog.tsx +173 -0
- package/template/apps/asas-tanstack/src/components/ui/avatar.tsx +104 -0
- package/template/apps/asas-tanstack/src/components/ui/badge.tsx +48 -0
- package/template/apps/asas-tanstack/src/components/ui/breadcrumb.tsx +125 -0
- package/template/apps/asas-tanstack/src/components/ui/button-group.tsx +87 -0
- package/template/apps/asas-tanstack/src/components/ui/button.tsx +56 -0
- package/template/apps/asas-tanstack/src/components/ui/calendar.tsx +223 -0
- package/template/apps/asas-tanstack/src/components/ui/card.tsx +94 -0
- package/template/apps/asas-tanstack/src/components/ui/chart.tsx +369 -0
- package/template/apps/asas-tanstack/src/components/ui/checkbox.tsx +27 -0
- package/template/apps/asas-tanstack/src/components/ui/collapsible.tsx +19 -0
- package/template/apps/asas-tanstack/src/components/ui/combobox.tsx +300 -0
- package/template/apps/asas-tanstack/src/components/ui/dialog.tsx +149 -0
- package/template/apps/asas-tanstack/src/components/ui/direction.tsx +5 -0
- package/template/apps/asas-tanstack/src/components/ui/directional-icon.tsx +20 -0
- package/template/apps/asas-tanstack/src/components/ui/dropdown-menu.tsx +267 -0
- package/template/apps/asas-tanstack/src/components/ui/field.tsx +225 -0
- package/template/apps/asas-tanstack/src/components/ui/input-group.tsx +147 -0
- package/template/apps/asas-tanstack/src/components/ui/input-otp.tsx +20 -0
- package/template/apps/asas-tanstack/src/components/ui/input.tsx +20 -0
- package/template/apps/asas-tanstack/src/components/ui/label.tsx +18 -0
- package/template/apps/asas-tanstack/src/components/ui/popover.tsx +50 -0
- package/template/apps/asas-tanstack/src/components/ui/radio-group.tsx +10 -0
- package/template/apps/asas-tanstack/src/components/ui/resizable.tsx +47 -0
- package/template/apps/asas-tanstack/src/components/ui/scroll-area.tsx +52 -0
- package/template/apps/asas-tanstack/src/components/ui/select.tsx +190 -0
- package/template/apps/asas-tanstack/src/components/ui/separator.tsx +23 -0
- package/template/apps/asas-tanstack/src/components/ui/sheet.tsx +127 -0
- package/template/apps/asas-tanstack/src/components/ui/sidebar.tsx +716 -0
- package/template/apps/asas-tanstack/src/components/ui/skeleton.tsx +13 -0
- package/template/apps/asas-tanstack/src/components/ui/slider.tsx +13 -0
- package/template/apps/asas-tanstack/src/components/ui/spinner.tsx +11 -0
- package/template/apps/asas-tanstack/src/components/ui/switch.tsx +8 -0
- package/template/apps/asas-tanstack/src/components/ui/table.tsx +119 -0
- package/template/apps/asas-tanstack/src/components/ui/tabs.tsx +80 -0
- package/template/apps/asas-tanstack/src/components/ui/textarea.tsx +18 -0
- package/template/apps/asas-tanstack/src/components/ui/toggle-group.tsx +8 -0
- package/template/apps/asas-tanstack/src/components/ui/toggle.tsx +44 -0
- package/template/apps/asas-tanstack/src/components/ui/tooltip.tsx +68 -0
- package/template/apps/asas-tanstack/src/components.ts +35 -0
- package/template/apps/asas-tanstack/src/copy.ts +1207 -0
- package/template/apps/asas-tanstack/src/first-run.ts +16 -0
- package/template/apps/asas-tanstack/src/hooks/use-mobile.ts +19 -0
- package/template/apps/asas-tanstack/src/lib/utils.ts +6 -0
- package/template/apps/asas-tanstack/src/links.ts +38 -0
- package/template/apps/asas-tanstack/src/locale-switch.tsx +28 -0
- package/template/apps/asas-tanstack/src/no-organization.tsx +108 -0
- package/template/apps/asas-tanstack/src/quiet-abort.ts +25 -0
- package/template/apps/asas-tanstack/src/redirect.ts +39 -0
- package/template/apps/asas-tanstack/src/request-headers.ts +11 -0
- package/template/apps/asas-tanstack/src/routeTree.gen.ts +424 -0
- package/template/apps/asas-tanstack/src/router.tsx +18 -0
- package/template/apps/asas-tanstack/src/routes/(screens)/dashboard/files.ts +11 -0
- package/template/apps/asas-tanstack/src/routes/(screens)/dashboard/screen.json +4242 -0
- package/template/apps/asas-tanstack/src/routes/(screens)/dashboard/types.ts +160 -0
- package/template/apps/asas-tanstack/src/routes/(screens)/dashboard.$.tsx +17 -0
- package/template/apps/asas-tanstack/src/routes/(screens)/dashboard.index.tsx +10 -0
- package/template/apps/asas-tanstack/src/routes/(screens)/dashboard.tsx +13 -0
- package/template/apps/asas-tanstack/src/routes/(screens)/portal/files.ts +9 -0
- package/template/apps/asas-tanstack/src/routes/(screens)/portal/screen.json +1564 -0
- package/template/apps/asas-tanstack/src/routes/(screens)/portal/types.ts +94 -0
- package/template/apps/asas-tanstack/src/routes/(screens)/portal.$.tsx +17 -0
- package/template/apps/asas-tanstack/src/routes/(screens)/portal.index.tsx +10 -0
- package/template/apps/asas-tanstack/src/routes/(screens)/portal.tsx +13 -0
- package/template/apps/asas-tanstack/src/routes/__root.tsx +99 -0
- package/template/apps/asas-tanstack/src/routes/api/$.ts +11 -0
- package/template/apps/asas-tanstack/src/routes/auth.accept-invitation.tsx +108 -0
- package/template/apps/asas-tanstack/src/routes/auth.first-run.tsx +114 -0
- package/template/apps/asas-tanstack/src/routes/auth.forgot-password.tsx +94 -0
- package/template/apps/asas-tanstack/src/routes/auth.handoff.ts +39 -0
- package/template/apps/asas-tanstack/src/routes/auth.reset-password.tsx +16 -0
- package/template/apps/asas-tanstack/src/routes/auth.set-password.tsx +16 -0
- package/template/apps/asas-tanstack/src/routes/auth.sign-in.tsx +98 -0
- package/template/apps/asas-tanstack/src/routes/auth.sign-up.tsx +143 -0
- package/template/apps/asas-tanstack/src/routes/index.tsx +146 -0
- package/template/apps/asas-tanstack/src/routes/unauthorized.tsx +134 -0
- package/template/apps/asas-tanstack/src/screen-form.tsx +36 -0
- package/template/apps/asas-tanstack/src/screen-list.tsx +140 -0
- package/template/apps/asas-tanstack/src/screen-names.ts +10 -0
- package/template/apps/asas-tanstack/src/screens.tsx +888 -0
- package/template/apps/asas-tanstack/src/server.ts +26 -0
- package/template/apps/asas-tanstack/src/slide.ts +22 -0
- package/template/apps/asas-tanstack/src/start.ts +57 -0
- package/template/apps/asas-tanstack/src/styles.css +163 -0
- package/template/apps/asas-tanstack/src/theme.ts +5 -0
- package/template/apps/asas-tanstack/tsconfig.json +19 -0
- package/template/apps/asas-tanstack/vite.config.ts +34 -0
- package/template/package.json +16 -0
- package/template/templates/asas/.claude/skills/add-field/SKILL.md +27 -0
- package/template/templates/asas/.claude/skills/add-kayan/SKILL.md +26 -0
- package/template/templates/asas/.claude/skills/eject-admin-piece/SKILL.md +28 -0
- package/template/templates/asas/.claude/skills/upgrade-mithaq/SKILL.md +35 -0
- package/template/templates/asas/.env.example +33 -0
- package/template/templates/asas/AGENTS.md +101 -0
- package/template/templates/asas/CLAUDE.md +1 -0
- package/template/templates/asas/README.md +1056 -0
- package/template/templates/asas/mithaq.hints.json +25 -0
- package/template/templates/asas/package.json +53 -0
- package/template/templates/asas/src/asas.ts +118 -0
- package/template/templates/asas/src/backoffice-http.ts +117 -0
- package/template/templates/asas/src/dev-setup.ts +112 -0
- package/template/templates/asas/src/local-database.ts +22 -0
- package/template/templates/asas/src/messages/account.json +132 -0
- package/template/templates/asas/src/messages/auditLog.json +304 -0
- package/template/templates/asas/src/messages/backofficeLog.json +132 -0
- package/template/templates/asas/src/messages/courses.json +312 -0
- package/template/templates/asas/src/messages/enrollments.json +60 -0
- package/template/templates/asas/src/messages/invitation.json +82 -0
- package/template/templates/asas/src/messages/localUsers.json +48 -0
- package/template/templates/asas/src/messages/media.json +76 -0
- package/template/templates/asas/src/messages/member.json +62 -0
- package/template/templates/asas/src/messages/memberRoles.json +48 -0
- package/template/templates/asas/src/messages/mithaq.json +214 -0
- package/template/templates/asas/src/messages/organization.json +72 -0
- package/template/templates/asas/src/messages/organizationRole.json +62 -0
- package/template/templates/asas/src/messages/roles.json +72 -0
- package/template/templates/asas/src/messages/session.json +102 -0
- package/template/templates/asas/src/messages/sessions.json +136 -0
- package/template/templates/asas/src/messages/settings.json +64 -0
- package/template/templates/asas/src/messages/tags.json +48 -0
- package/template/templates/asas/src/messages/user.json +112 -0
- package/template/templates/asas/src/messages/verification.json +62 -0
- package/template/templates/asas/src/migrations/20260920080701_parched_tombstone/migration.sql +177 -0
- package/template/templates/asas/src/migrations/20260920080701_parched_tombstone/snapshot.json +2169 -0
- package/template/templates/asas/src/migrations/20260920230505_zippy_ben_urich/migration.sql +1 -0
- package/template/templates/asas/src/migrations/20260920230505_zippy_ben_urich/snapshot.json +2182 -0
- package/template/templates/asas/src/migrations/20260920231219_slim_retro_girl/migration.sql +20 -0
- package/template/templates/asas/src/migrations/20260920231219_slim_retro_girl/snapshot.json +2409 -0
- package/template/templates/asas/src/migrations/20260922082945_military_ironclad/migration.sql +15 -0
- package/template/templates/asas/src/migrations/20260922082945_military_ironclad/snapshot.json +2627 -0
- package/template/templates/asas/src/migrations/20260922112630_bitter_chat/migration.sql +5 -0
- package/template/templates/asas/src/migrations/20260922112630_bitter_chat/snapshot.json +2691 -0
- package/template/templates/asas/src/migrations/20260923235915_foamy_rachel_grey/migration.sql +8 -0
- package/template/templates/asas/src/migrations/20260923235915_foamy_rachel_grey/snapshot.json +2795 -0
- package/template/templates/asas/src/migrations/20260926145709_clean_the_initiative/migration.sql +3 -0
- package/template/templates/asas/src/migrations/20260926145709_clean_the_initiative/snapshot.json +2834 -0
- package/template/templates/asas/src/migrations/20260927212525_bent_prowler/migration.sql +9 -0
- package/template/templates/asas/src/migrations/20260927212525_bent_prowler/snapshot.json +2870 -0
- package/template/templates/asas/src/migrations/20260927223441_tranquil_bromley/migration.sql +1 -0
- package/template/templates/asas/src/migrations/20260927223441_tranquil_bromley/snapshot.json +2881 -0
- package/template/templates/asas/src/migrations/20260928030047_outgoing_wraith/migration.sql +15 -0
- package/template/templates/asas/src/migrations/20260928030047_outgoing_wraith/snapshot.json +3073 -0
- package/template/templates/asas/src/migrations/20260929024407_grey_morlun/migration.sql +21 -0
- package/template/templates/asas/src/migrations/20260929024407_grey_morlun/snapshot.json +3098 -0
- package/template/templates/asas/src/migrations/20260929130530_bored_jackal/migration.sql +21 -0
- package/template/templates/asas/src/migrations/20260929130530_bored_jackal/snapshot.json +3124 -0
- package/template/templates/asas/src/migrations/20260930102924_material_newton_destine/migration.sql +32 -0
- package/template/templates/asas/src/migrations/20260930102924_material_newton_destine/snapshot.json +3324 -0
- package/template/templates/asas/src/migrations/20261003022353_clumsy_taskmaster/migration.sql +2 -0
- package/template/templates/asas/src/migrations/20261003022353_clumsy_taskmaster/snapshot.json +3350 -0
- package/template/templates/asas/src/migrations/20261003143249_premium_red_shift/migration.sql +21 -0
- package/template/templates/asas/src/migrations/20261003143249_premium_red_shift/snapshot.json +3635 -0
- package/template/templates/asas/src/migrations/20261008215349_square_norrin_radd/migration.sql +8 -0
- package/template/templates/asas/src/migrations/20261008215349_square_norrin_radd/snapshot.json +3635 -0
- package/template/templates/asas/src/migrations/20261008230204_many_scarecrow/migration.sql +18 -0
- package/template/templates/asas/src/migrations/20261008230204_many_scarecrow/snapshot.json +3635 -0
- package/template/templates/asas/src/migrations/20261010005521_elite_giant_girl/migration.sql +18 -0
- package/template/templates/asas/src/migrations/20261010005521_elite_giant_girl/snapshot.json +3635 -0
- package/template/templates/asas/src/migrations/20261010120822_needy_thunderbolt/migration.sql +11 -0
- package/template/templates/asas/src/migrations/20261010120822_needy_thunderbolt/snapshot.json +3667 -0
- package/template/templates/asas/src/migrations/20261012000752_organization_ownership/migration.sql +48 -0
- package/template/templates/asas/src/migrations/20261012000752_organization_ownership/snapshot.json +3891 -0
- package/template/templates/asas/src/migrations/20261014221355_tags_restrict/migration.sql +1 -0
- package/template/templates/asas/src/migrations/20261014221355_tags_restrict/snapshot.json +3881 -0
- package/template/templates/asas/src/migrations/20261014222218_one_seat_per_session/migration.sql +1 -0
- package/template/templates/asas/src/migrations/20261014222218_one_seat_per_session/snapshot.json +3894 -0
- package/template/templates/asas/src/migrations/20261014223522_session_archive_reason/migration.sql +1 -0
- package/template/templates/asas/src/migrations/20261014223522_session_archive_reason/snapshot.json +3907 -0
- package/template/templates/asas/src/migrations/20261014225728_course_archive_by_operation/migration.sql +1 -0
- package/template/templates/asas/src/migrations/20261014225728_course_archive_by_operation/snapshot.json +3907 -0
- package/template/templates/asas/src/migrations/20261015042444_organization_names/migration.sql +1 -0
- package/template/templates/asas/src/migrations/20261015042444_organization_names/snapshot.json +3920 -0
- package/template/templates/asas/src/migrations/20261015053212_member_last_seen/migration.sql +1 -0
- package/template/templates/asas/src/migrations/20261015053212_member_last_seen/snapshot.json +3933 -0
- package/template/templates/asas/src/migrations/20261015093203_activity_and_staff_history/migration.sql +15 -0
- package/template/templates/asas/src/migrations/20261015093203_activity_and_staff_history/snapshot.json +4113 -0
- package/template/templates/asas/src/migrations/20261015095752_portal/migration.sql +2 -0
- package/template/templates/asas/src/migrations/20261015095752_portal/snapshot.json +4113 -0
- package/template/templates/asas/src/migrations/20261015135529_better_auth_indexes/migration.sql +9 -0
- package/template/templates/asas/src/migrations/20261015135529_better_auth_indexes/snapshot.json +4302 -0
- package/template/templates/asas/src/migrations/20261015162438_audit_changes_json/migration.sql +27 -0
- package/template/templates/asas/src/migrations/20261015162438_audit_changes_json/snapshot.json +4289 -0
- package/template/templates/asas/src/migrations/drizzle.config.ts +11 -0
- package/template/templates/asas/src/migrations/schema.ts +30 -0
- package/template/templates/asas/src/mithaq.ts +4 -0
- package/template/templates/asas/src/organizations.ts +3 -0
- package/template/templates/asas/src/seed.ts +427 -0
- package/template/templates/asas/src/ui-backoffice/home.tsx +63 -0
- package/template/templates/asas/src/ui-backoffice/organization-actions.tsx +121 -0
- package/template/templates/asas/src/ui-backoffice/record-page.tsx +30 -0
- package/template/templates/asas/src/ui-backoffice/role-cells.tsx +59 -0
- package/template/templates/asas/src/ui-backoffice/user-actions.tsx +249 -0
- package/template/templates/asas/src/ui-dashboard/dashboard.tsx +300 -0
- package/template/templates/asas/src/ui-dashboard/home.tsx +73 -0
- package/template/templates/asas/src/ui-dashboard/members-card.tsx +147 -0
- package/template/templates/asas/src/ui-dashboard/members.tsx +829 -0
- package/template/templates/asas/src/ui-dashboard/theme-provider.tsx +10 -0
- package/template/templates/asas/src/ui-dashboard/versions.tsx +446 -0
- package/template/templates/asas/src/ui-portal/courses-home.tsx +96 -0
- package/template/templates/asas/src/ui-portal/home.tsx +73 -0
- package/template/templates/asas/src/ui-portal/page.tsx +11 -0
- package/template/templates/features/audit-log/audit-log/audit-log.ts +284 -0
- package/template/templates/features/audit-log/backoffice-log/backoffice-log.ts +67 -0
- package/template/templates/features/audit-log/index.ts +4 -0
- package/template/templates/features/audit-log/package.json +13 -0
- package/template/templates/features/auth/index.ts +11 -0
- package/template/templates/features/auth/local-users/local-users.ts +143 -0
- package/template/templates/features/auth/package.json +13 -0
- package/template/templates/features/auth/user/account.access.ts +8 -0
- package/template/templates/features/auth/user/account.ts +31 -0
- package/template/templates/features/auth/user/index.ts +18 -0
- package/template/templates/features/auth/user/invitation.access.ts +4 -0
- package/template/templates/features/auth/user/invitation.ts +27 -0
- package/template/templates/features/auth/user/member.access.ts +10 -0
- package/template/templates/features/auth/user/member.screens.ts +37 -0
- package/template/templates/features/auth/user/member.ts +26 -0
- package/template/templates/features/auth/user/organization.access.ts +20 -0
- package/template/templates/features/auth/user/organization.screens.ts +37 -0
- package/template/templates/features/auth/user/organization.ts +25 -0
- package/template/templates/features/auth/user/organizationRole.access.ts +8 -0
- package/template/templates/features/auth/user/organizationRole.ts +25 -0
- package/template/templates/features/auth/user/session.access.ts +8 -0
- package/template/templates/features/auth/user/session.ts +28 -0
- package/template/templates/features/auth/user/user.access.ts +30 -0
- package/template/templates/features/auth/user/user.screens.ts +45 -0
- package/template/templates/features/auth/user/user.ts +31 -0
- package/template/templates/features/auth/user/verification.access.ts +8 -0
- package/template/templates/features/auth/user/verification.ts +23 -0
- package/template/templates/features/courses/courses/courses.ts +601 -0
- package/template/templates/features/courses/courses/cover-reads.ts +33 -0
- package/template/templates/features/courses/courses/ui/archived-badge.tsx +9 -0
- package/template/templates/features/courses/courses/ui/fee-cell.tsx +19 -0
- package/template/templates/features/courses/courses/ui/no-courses.tsx +13 -0
- package/template/templates/features/courses/courses/ui/status-cell.tsx +33 -0
- package/template/templates/features/courses/courses/ui/unpublish-button.tsx +15 -0
- package/template/templates/features/courses/domain/archive.ts +39 -0
- package/template/templates/features/courses/domain/on-offer.ts +6 -0
- package/template/templates/features/courses/enrollments/enrollments.ts +309 -0
- package/template/templates/features/courses/enrollments/ui/session-cell.tsx +75 -0
- package/template/templates/features/courses/enrollments/ui/session-labels.tsx +36 -0
- package/template/templates/features/courses/index.ts +8 -0
- package/template/templates/features/courses/package.json +24 -0
- package/template/templates/features/courses/portal/ui/catalogue.tsx +86 -0
- package/template/templates/features/courses/portal/ui/course.tsx +176 -0
- package/template/templates/features/courses/portal/ui/enrollments.tsx +170 -0
- package/template/templates/features/courses/portal/ui/parts.tsx +95 -0
- package/template/templates/features/courses/portal/ui/reads.ts +76 -0
- package/template/templates/features/courses/portal/ui/rules.ts +87 -0
- package/template/templates/features/courses/portal/ui/shell.tsx +194 -0
- package/template/templates/features/courses/sessions/seats.ts +42 -0
- package/template/templates/features/courses/sessions/sessions.ts +186 -0
- package/template/templates/features/media/index.ts +10 -0
- package/template/templates/features/media/media/media.ts +131 -0
- package/template/templates/features/media/media/ui/preview.tsx +143 -0
- package/template/templates/features/media/package.json +19 -0
- package/template/templates/features/roles/index.ts +4 -0
- package/template/templates/features/roles/member-roles/member-roles.ts +207 -0
- package/template/templates/features/roles/package.json +21 -0
- package/template/templates/features/roles/roles/roles.ts +184 -0
- package/template/templates/features/roles/roles/ui/role-form.tsx +267 -0
- package/template/templates/features/roles/roles/ui/roles.tsx +190 -0
- package/template/templates/features/settings/index.ts +3 -0
- package/template/templates/features/settings/package.json +13 -0
- package/template/templates/features/settings/settings/settings.ts +64 -0
- package/template/templates/features/tags/index.ts +3 -0
- package/template/templates/features/tags/package.json +14 -0
- package/template/templates/features/tags/tags/tags.ts +80 -0
- package/template/templates/mithaq/components.json +22 -0
- package/template/templates/mithaq/package.json +33 -0
- package/template/templates/mithaq/src/mail/index.ts +32 -0
- package/template/templates/mithaq/src/mail/mailers.ts +36 -0
- package/template/templates/mithaq/src/mithaq/audit-sink.ts +111 -0
- package/template/templates/mithaq/src/mithaq/auth/backoffice-roles.ts +108 -0
- package/template/templates/mithaq/src/mithaq/auth/index.ts +1859 -0
- package/template/templates/mithaq/src/mithaq/auth/organizations.ts +80 -0
- package/template/templates/mithaq/src/mithaq/pages.ts +83 -0
- package/template/templates/mithaq/src/mithaq/rich-text-nodes.ts +19 -0
- package/template/templates/mithaq/src/mithaq.ts +593 -0
- package/template/templates/mithaq/src/roles/default-member-roles.ts +29 -0
- package/template/templates/mithaq/src/roles/grants.ts +47 -0
- package/template/templates/mithaq/src/roles/member-access.ts +11 -0
- package/template/templates/mithaq/src/roles/statements.ts +13 -0
- package/template/templates/mithaq/src/roles/system-roles.ts +16 -0
- package/template/templates/mithaq/src/roles/tenant-access.ts +260 -0
- package/template/templates/mithaq/src/roles/tenant-roles.ts +321 -0
- package/template/templates/mithaq/src/steps/expected-updated-at.ts +41 -0
- package/template/templates/mithaq/src/storage/defaults.ts +156 -0
- package/template/templates/mithaq/src/storage/index.ts +97 -0
- package/template/templates/mithaq/src/storage/local.ts +143 -0
- package/template/templates/mithaq/src/storage/r2.ts +5 -0
- package/template/templates/mithaq/src/storage/s3.ts +91 -0
- package/template/templates/mithaq/src/storage/uploadthing.ts +59 -0
- package/template/templates/mithaq/src/ui/activity-page.tsx +33 -0
- package/template/templates/mithaq/src/ui/activity.tsx +527 -0
- package/template/templates/mithaq/src/ui/app-shell.tsx +268 -0
- package/template/templates/mithaq/src/ui/kpi-card.tsx +25 -0
- package/template/templates/mithaq/src/ui/record-page.tsx +50 -0
- package/template/templates/mithaq/src/ui/rich-text-nodes.tsx +33 -0
- package/template/templates/mithaq/src/ui/screen-nav.tsx +28 -0
- package/template/templates/mithaq/src/ui/table-page.tsx +9 -0
- package/template/templates/mithaq/src/ui/top-shell.tsx +60 -0
- package/README.md +0 -3
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import handler, { createServerEntry } from '@tanstack/react-start/server-entry'
|
|
2
|
+
import type { ScreenClient } from 'mithaq/admin'
|
|
3
|
+
import { checkComponents } from 'mithaq-admin/components.tsx'
|
|
4
|
+
import { components } from './components.ts'
|
|
5
|
+
import { withQuietAbort } from './quiet-abort.ts'
|
|
6
|
+
|
|
7
|
+
// Every screen this app serves, checked against its components map as it starts, so a field whose kind has no
|
|
8
|
+
// control fails the start, naming the kind and the field, and never reaches a page. Read on the server alone,
|
|
9
|
+
// since a screen.json names every field of the screen.
|
|
10
|
+
for (const client of Object.values(import.meta.glob<ScreenClient>('./routes/(screens)/*/screen.json', { eager: true, import: 'default' }))) {
|
|
11
|
+
checkComponents({ client, components })
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// A production start connects once before handing on any request, and `connect()` refuses to
|
|
15
|
+
// start while a migration is unapplied; a refused start exits 1. NODE_ENV is read off `process`
|
|
16
|
+
// so Vite cannot replace it at build time, and a built server started without
|
|
17
|
+
// `NODE_ENV=production` never connects, which would push into the deploy's database.
|
|
18
|
+
const { env } = process
|
|
19
|
+
if (env.NODE_ENV === 'production') {
|
|
20
|
+
await (await import('asas')).asas.connect().catch((error: unknown) => {
|
|
21
|
+
console.error(error)
|
|
22
|
+
process.exit(1)
|
|
23
|
+
})
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export default createServerEntry({ fetch: (request: Request) => handler.fetch(withQuietAbort(request)) })
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The provider's own session read, which refreshes a session past its `updateAge` and forwards the cookie.
|
|
3
|
+
* Run it before the actor is resolved: a read that refreshes the row first leaves this one nothing due.
|
|
4
|
+
*/
|
|
5
|
+
export const slide = async ({
|
|
6
|
+
strategies,
|
|
7
|
+
headers,
|
|
8
|
+
setResponseHeader,
|
|
9
|
+
}: {
|
|
10
|
+
strategies: readonly unknown[]
|
|
11
|
+
headers: Headers
|
|
12
|
+
setResponseHeader: (name: 'set-cookie', value: string[]) => void
|
|
13
|
+
}) => {
|
|
14
|
+
const cookies: string[] = []
|
|
15
|
+
for (const strategy of strategies) {
|
|
16
|
+
const read = (strategy as { server?: { api?: { getSession?: (args: object) => Promise<{ headers: Headers }> } } }).server?.api?.getSession
|
|
17
|
+
if (read) cookies.push(...(await read({ headers, returnHeaders: true })).headers.getSetCookie())
|
|
18
|
+
}
|
|
19
|
+
// Set once with every strategy's cookies: a second set replaces the first.
|
|
20
|
+
if (cookies.length) setResponseHeader('set-cookie', cookies)
|
|
21
|
+
}
|
|
22
|
+
// mithaq-admin 2d3ab739c92c6c2b397041b76bf4b23b2902b7a2 bc0221e1088103f8638e0333b84aafb6b326e3991a187ced198bce2d090ecbe9
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { createCsrfMiddleware, createMiddleware, createStart } from '@tanstack/react-start'
|
|
2
|
+
import { dirOf, localeCookie, localeOf } from './copy.ts'
|
|
3
|
+
|
|
4
|
+
// The locale is resolved once per request, before any route runs, because the document's `lang`
|
|
5
|
+
// and `dir` are written before a loader exists. Nothing here imports
|
|
6
|
+
// `@tanstack/react-start/server`: both builds reach this entry, so it would put server code in the client.
|
|
7
|
+
|
|
8
|
+
/** No `decodeURIComponent`: the only caller refuses every value but two ASCII names. */
|
|
9
|
+
const cookieOf = (header: string | null, name: string): string | undefined =>
|
|
10
|
+
header
|
|
11
|
+
?.split(';')
|
|
12
|
+
.map((one) => one.trim().split('='))
|
|
13
|
+
.find(([key]) => key === name)
|
|
14
|
+
?.slice(1)
|
|
15
|
+
.join('=')
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* The request's locale and direction, off the `locale` cookie alone: `Accept-Language` is not a
|
|
19
|
+
* choice the viewer made.
|
|
20
|
+
*/
|
|
21
|
+
const locale = createMiddleware({ type: 'request' }).server(({ request, next }) => {
|
|
22
|
+
const asked = localeOf(cookieOf(request.headers.get('cookie'), localeCookie))
|
|
23
|
+
return next({ context: { locale: asked, dir: dirOf(asked) } })
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
/** Refuses a server function reached from outside the page; page renders and `/api` are untouched. */
|
|
27
|
+
const csrf = createCsrfMiddleware({ filter: (ctx) => ctx.handlerType === 'serverFn' })
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* `/admin` answers a 308 to the same path under `/dashboard`, so a saved link still lands with its
|
|
31
|
+
* method and body. The location is a path, never a URL, so the request's host header never reaches it.
|
|
32
|
+
*/
|
|
33
|
+
const moved = createMiddleware({ type: 'request' }).server(({ request, next }) => {
|
|
34
|
+
const url = new URL(request.url)
|
|
35
|
+
if (!/^\/admin(\/|$)/.test(url.pathname)) return next()
|
|
36
|
+
return new Response(null, { status: 308, headers: { location: `/dashboard${url.pathname.slice('/admin'.length)}${url.search}` } })
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Only this origin may frame this app's pages, so no other site can lay it under its own page and
|
|
41
|
+
* steer a click. First, so it covers every other middleware's answer; rebuilt, since a redirect's
|
|
42
|
+
* headers are immutable.
|
|
43
|
+
*/
|
|
44
|
+
const framing = createMiddleware({ type: 'request' }).server(async ({ next }) => {
|
|
45
|
+
const result = await next()
|
|
46
|
+
const answer = result.response
|
|
47
|
+
const html = answer.headers.get('content-type')?.startsWith('text/html') === true
|
|
48
|
+
if (answer.headers.has('content-security-policy') && !html) return result
|
|
49
|
+
const headers = new Headers(answer.headers)
|
|
50
|
+
if (!headers.has('content-security-policy')) headers.set('content-security-policy', "frame-ancestors 'self'")
|
|
51
|
+
// No HTML answer is cached: each is drawn for one request's session and locale, so a page
|
|
52
|
+
// someone signed out of must not come back from the cache on Back.
|
|
53
|
+
if (html) headers.set('cache-control', 'no-store')
|
|
54
|
+
return { ...result, response: new Response(answer.body, { status: answer.status, statusText: answer.statusText, headers }) }
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
export const startInstance = createStart(() => ({ requestMiddleware: [framing, moved, csrf, locale] }))
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/* Theme copied wholesale from tanstack-business:apps/web/src/styles.css:
|
|
2
|
+
imports, custom-variant, :root and .dark variables, the @theme inline
|
|
3
|
+
block and the @layer base rules, unchanged. Only the @source line below
|
|
4
|
+
differs, pointing at this project's template instead of TB's monorepo.
|
|
5
|
+
Tailwind finds this app's own files, an ejected `src/components/mithaq`
|
|
6
|
+
among them, without one. */
|
|
7
|
+
@import 'tailwindcss';
|
|
8
|
+
@import 'tw-animate-css';
|
|
9
|
+
@import 'shadcn/tailwind.css';
|
|
10
|
+
/* The admin's pieces in node_modules, which Tailwind never scans on its own. */
|
|
11
|
+
@import 'mithaq-admin/source.css';
|
|
12
|
+
@import '@fontsource-variable/raleway';
|
|
13
|
+
@import '@fontsource/ibm-plex-sans-arabic';
|
|
14
|
+
|
|
15
|
+
/* The project's own shells, pages and components, which the screens load
|
|
16
|
+
(the language package's `src/ui/app-shell.tsx`), in every package of the project.
|
|
17
|
+
Named by their folder, which every package manager leaves where it is, since
|
|
18
|
+
each links the package elsewhere. */
|
|
19
|
+
@source '../../../templates';
|
|
20
|
+
|
|
21
|
+
@custom-variant dark (&:is(.dark *));
|
|
22
|
+
|
|
23
|
+
:root {
|
|
24
|
+
--background: oklch(1 0 0);
|
|
25
|
+
--foreground: oklch(0.147 0.004 49.25);
|
|
26
|
+
--card: oklch(1 0 0);
|
|
27
|
+
--card-foreground: oklch(0.147 0.004 49.25);
|
|
28
|
+
--popover: oklch(1 0 0);
|
|
29
|
+
--popover-foreground: oklch(0.147 0.004 49.25);
|
|
30
|
+
--primary: oklch(0.216 0.006 56.043);
|
|
31
|
+
--primary-foreground: oklch(0.985 0.001 106.423);
|
|
32
|
+
--secondary: oklch(0.97 0.001 106.424);
|
|
33
|
+
--secondary-foreground: oklch(0.216 0.006 56.043);
|
|
34
|
+
--muted: oklch(0.97 0.001 106.424);
|
|
35
|
+
--muted-foreground: oklch(0.553 0.013 58.071);
|
|
36
|
+
--accent: oklch(0.97 0.001 106.424);
|
|
37
|
+
--accent-foreground: oklch(0.216 0.006 56.043);
|
|
38
|
+
/* Darker than the preset's red 600, which is 4.0:1 on the pale red fill the destructive button and menu item draw it on and 3.3:1 on its hover; this is 5.9:1 on the fill and 4.9:1 on the hover. */
|
|
39
|
+
--destructive: oklch(0.48 0.2 27.5);
|
|
40
|
+
--border: oklch(0.923 0.003 48.717);
|
|
41
|
+
--input: oklch(0.923 0.003 48.717);
|
|
42
|
+
--ring: oklch(0.709 0.01 56.259);
|
|
43
|
+
--chart-1: oklch(0.646 0.222 41.116);
|
|
44
|
+
--chart-2: oklch(0.6 0.118 184.704);
|
|
45
|
+
--chart-3: oklch(0.398 0.07 227.392);
|
|
46
|
+
--chart-4: oklch(0.828 0.189 84.429);
|
|
47
|
+
--chart-5: oklch(0.769 0.188 70.08);
|
|
48
|
+
--radius: 0.625rem;
|
|
49
|
+
--sidebar: oklch(0.985 0.001 106.423);
|
|
50
|
+
--sidebar-foreground: oklch(0.147 0.004 49.25);
|
|
51
|
+
--sidebar-primary: oklch(0.216 0.006 56.043);
|
|
52
|
+
--sidebar-primary-foreground: oklch(0.985 0.001 106.423);
|
|
53
|
+
--sidebar-accent: oklch(0.97 0.001 106.424);
|
|
54
|
+
--sidebar-accent-foreground: oklch(0.216 0.006 56.043);
|
|
55
|
+
--sidebar-border: oklch(0.923 0.003 48.717);
|
|
56
|
+
--sidebar-ring: oklch(0.709 0.01 56.259);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.dark {
|
|
60
|
+
--background: oklch(0.147 0.004 49.25);
|
|
61
|
+
--foreground: oklch(0.985 0.001 106.423);
|
|
62
|
+
--card: oklch(0.216 0.006 56.043);
|
|
63
|
+
--card-foreground: oklch(0.985 0.001 106.423);
|
|
64
|
+
--popover: oklch(0.216 0.006 56.043);
|
|
65
|
+
--popover-foreground: oklch(0.985 0.001 106.423);
|
|
66
|
+
--primary: oklch(0.923 0.003 48.717);
|
|
67
|
+
--primary-foreground: oklch(0.216 0.006 56.043);
|
|
68
|
+
--secondary: oklch(0.268 0.007 34.298);
|
|
69
|
+
--secondary-foreground: oklch(0.985 0.001 106.423);
|
|
70
|
+
--muted: oklch(0.268 0.007 34.298);
|
|
71
|
+
--muted-foreground: oklch(0.709 0.01 56.259);
|
|
72
|
+
--accent: oklch(0.268 0.007 34.298);
|
|
73
|
+
--accent-foreground: oklch(0.985 0.001 106.423);
|
|
74
|
+
--destructive: oklch(0.704 0.191 22.216);
|
|
75
|
+
--border: oklch(1 0 0 / 10%);
|
|
76
|
+
--input: oklch(1 0 0 / 15%);
|
|
77
|
+
--ring: oklch(0.553 0.013 58.071);
|
|
78
|
+
--chart-1: oklch(0.488 0.243 264.376);
|
|
79
|
+
--chart-2: oklch(0.696 0.17 162.48);
|
|
80
|
+
--chart-3: oklch(0.769 0.188 70.08);
|
|
81
|
+
--chart-4: oklch(0.627 0.265 303.9);
|
|
82
|
+
--chart-5: oklch(0.645 0.246 16.439);
|
|
83
|
+
--sidebar: oklch(0.216 0.006 56.043);
|
|
84
|
+
--sidebar-foreground: oklch(0.985 0.001 106.423);
|
|
85
|
+
--sidebar-primary: oklch(0.488 0.243 264.376);
|
|
86
|
+
--sidebar-primary-foreground: oklch(0.985 0.001 106.423);
|
|
87
|
+
--sidebar-accent: oklch(0.268 0.007 34.298);
|
|
88
|
+
--sidebar-accent-foreground: oklch(0.985 0.001 106.423);
|
|
89
|
+
--sidebar-border: oklch(1 0 0 / 10%);
|
|
90
|
+
--sidebar-ring: oklch(0.553 0.013 58.071);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
@theme inline {
|
|
94
|
+
--font-sans: 'IBM Plex Sans Arabic', 'Raleway', sans-serif;
|
|
95
|
+
--color-sidebar-ring: var(--sidebar-ring);
|
|
96
|
+
--color-sidebar-border: var(--sidebar-border);
|
|
97
|
+
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
|
98
|
+
--color-sidebar-accent: var(--sidebar-accent);
|
|
99
|
+
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
|
100
|
+
--color-sidebar-primary: var(--sidebar-primary);
|
|
101
|
+
--color-sidebar-foreground: var(--sidebar-foreground);
|
|
102
|
+
--color-sidebar: var(--sidebar);
|
|
103
|
+
--color-chart-5: var(--chart-5);
|
|
104
|
+
--color-chart-4: var(--chart-4);
|
|
105
|
+
--color-chart-3: var(--chart-3);
|
|
106
|
+
--color-chart-2: var(--chart-2);
|
|
107
|
+
--color-chart-1: var(--chart-1);
|
|
108
|
+
--color-ring: var(--ring);
|
|
109
|
+
--color-input: var(--input);
|
|
110
|
+
--color-border: var(--border);
|
|
111
|
+
--color-destructive: var(--destructive);
|
|
112
|
+
--color-accent-foreground: var(--accent-foreground);
|
|
113
|
+
--color-accent: var(--accent);
|
|
114
|
+
--color-muted-foreground: var(--muted-foreground);
|
|
115
|
+
--color-muted: var(--muted);
|
|
116
|
+
--color-secondary-foreground: var(--secondary-foreground);
|
|
117
|
+
--color-secondary: var(--secondary);
|
|
118
|
+
--color-primary-foreground: var(--primary-foreground);
|
|
119
|
+
--color-primary: var(--primary);
|
|
120
|
+
--color-popover-foreground: var(--popover-foreground);
|
|
121
|
+
--color-popover: var(--popover);
|
|
122
|
+
--color-card-foreground: var(--card-foreground);
|
|
123
|
+
--color-card: var(--card);
|
|
124
|
+
--color-foreground: var(--foreground);
|
|
125
|
+
--color-background: var(--background);
|
|
126
|
+
--radius-sm: calc(var(--radius) - 4px);
|
|
127
|
+
--radius-md: calc(var(--radius) - 2px);
|
|
128
|
+
--radius-lg: var(--radius);
|
|
129
|
+
--radius-xl: calc(var(--radius) + 4px);
|
|
130
|
+
--radius-2xl: calc(var(--radius) + 8px);
|
|
131
|
+
--radius-3xl: calc(var(--radius) + 12px);
|
|
132
|
+
--radius-4xl: calc(var(--radius) + 16px);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
@layer base {
|
|
136
|
+
* {
|
|
137
|
+
@apply border-border outline-ring/50;
|
|
138
|
+
}
|
|
139
|
+
body {
|
|
140
|
+
@apply font-sans bg-background text-foreground;
|
|
141
|
+
}
|
|
142
|
+
html {
|
|
143
|
+
@apply font-sans;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/* Fix: Make dropdown menu roots not affect layout */
|
|
148
|
+
[data-slot='dropdown-menu'] {
|
|
149
|
+
display: contents;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/* Fix: Ensure sidebar menu action dropdowns don't affect layout */
|
|
153
|
+
/* Fix: Ensure sidebar menu action dropdowns don't affect layout
|
|
154
|
+
Note: This was causing issues with SidebarMenuAction positioning. Removing display: contents from trigger.
|
|
155
|
+
*/
|
|
156
|
+
/* [data-sidebar='menu-item'] > [data-slot='dropdown-menu-trigger'] {
|
|
157
|
+
display: contents;
|
|
158
|
+
} */
|
|
159
|
+
|
|
160
|
+
/* Fix: Ensure sidebar footer content spans full width */
|
|
161
|
+
[data-sidebar='footer'] [data-slot='dropdown-menu-trigger'] {
|
|
162
|
+
width: 100%;
|
|
163
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "es2024",
|
|
4
|
+
"lib": ["es2024", "dom", "dom.iterable"],
|
|
5
|
+
"module": "preserve",
|
|
6
|
+
"moduleResolution": "bundler",
|
|
7
|
+
"jsx": "react-jsx",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"noUncheckedIndexedAccess": true,
|
|
10
|
+
"noEmit": true,
|
|
11
|
+
"skipLibCheck": true,
|
|
12
|
+
"erasableSyntaxOnly": true,
|
|
13
|
+
"allowImportingTsExtensions": true,
|
|
14
|
+
"resolveJsonModule": true,
|
|
15
|
+
"types": ["node", "vite/client"],
|
|
16
|
+
"paths": { "@/*": ["./src/*"], "mithaq-admin/*": ["./src/components/mithaq/*", "./node_modules/mithaq-admin/registry/*"] }
|
|
17
|
+
},
|
|
18
|
+
"include": ["src/**/*.ts", "src/**/*.tsx", "vite.config.ts", "../../templates/mithaq/src/ui/*.tsx", "../../templates/asas/src/ui-*/*.tsx", "../../templates/features/*/*/ui/*.tsx"]
|
|
19
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import tailwindcss from '@tailwindcss/vite'
|
|
2
|
+
import { tanstackStart } from '@tanstack/react-start/plugin/vite'
|
|
3
|
+
import viteReact from '@vitejs/plugin-react'
|
|
4
|
+
import { mithaqAdmin } from 'mithaq/vite'
|
|
5
|
+
import { defineConfig } from 'vite'
|
|
6
|
+
import { fileURLToPath } from 'node:url'
|
|
7
|
+
|
|
8
|
+
export default defineConfig({
|
|
9
|
+
// An alias rather than `resolve.tsconfigPaths`, which applies only to files the nearest
|
|
10
|
+
// tsconfig claims: the project's shells in the language package's `src/ui/` import `@/` too.
|
|
11
|
+
// `^@/` and not `@`, so `@tanstack/*` is left alone.
|
|
12
|
+
resolve: { alias: [{ find: /^@\//, replacement: fileURLToPath(new URL('./src/', import.meta.url)) }] },
|
|
13
|
+
plugins: [
|
|
14
|
+
tailwindcss(),
|
|
15
|
+
// A file under this folder takes the place of mithaq-admin's file of the same name, for every importer.
|
|
16
|
+
mithaqAdmin(fileURLToPath(new URL('./src/components/mithaq/', import.meta.url))),
|
|
17
|
+
// `mithaq generate screens` writes `types.ts` and `files.ts` beside the route files, and neither is a route.
|
|
18
|
+
tanstackStart({ router: { routeFileIgnorePattern: '^(files|types)\\.ts$' } }),
|
|
19
|
+
viteReact(),
|
|
20
|
+
],
|
|
21
|
+
// Behind the proxy that routes by Host: bound to the loopback address it targets, and answering
|
|
22
|
+
// the public name in BETTER_AUTH_URL, which Vite refuses in a Host header unless named here.
|
|
23
|
+
preview: { host: '127.0.0.1', allowedHosts: process.env.BETTER_AUTH_URL ? [new URL(process.env.BETTER_AUTH_URL).hostname] : [] },
|
|
24
|
+
environments: {
|
|
25
|
+
ssr: {
|
|
26
|
+
// `asas` and `mithaq` stay external: the drizzle adapter imports `drizzle-kit/api-postgres`
|
|
27
|
+
// behind a `webpackIgnore` comment Vite does not honour, and bundled, the build fails on
|
|
28
|
+
// drizzle's optional peers. The dev server reads `resolve.external`, the build reads
|
|
29
|
+
// `build.rollupOptions.external`, so both are set.
|
|
30
|
+
resolve: { external: ['asas', 'mithaq'] },
|
|
31
|
+
build: { rollupOptions: { external: [/^asas$/, /^mithaq(\/|$)/] } },
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
})
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: add-field
|
|
3
|
+
description: Add, change or remove a field of an existing kayan in this mithaq project and write the migration for it. Use when asked to add a column, change a field's kind or rules, or write a migration.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Add a field and its migration
|
|
7
|
+
|
|
8
|
+
The guide is "A field" under "Add a feature to an existing kayan" in `README.md`, and "Migrations" in `AGENTS.md`. The installed mithaq is `packages/asas/node_modules/mithaq/`, or `node_modules/mithaq/` where the package manager hoists it to the root: every kind and rule is in its `docs/packages/mithaq/README.md`, and `mithaq migrate` in its `docs/packages/mithaq/src/asas/cli/README.md`.
|
|
9
|
+
|
|
10
|
+
1. Edit `fields` in the kayan's file. A kind or rule the language does not hold changes the vocabulary: stop and ask the developer.
|
|
11
|
+
2. A new `required` field on a table with rows needs a literal `defaultValue`, or goes in without `required` and becomes required in a later migration.
|
|
12
|
+
3. Add the field to the pages that should draw it, and to the roles' grants when they list fields one by one (`<kayan>.fields.<field>`).
|
|
13
|
+
4. From `packages/asas/`, with `DATABASE_URL` pointing at a database built from the migrations (never a pushed one; `AGENTS.md` "Migrations" says how to build one):
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
bunx mithaq generate screens # when a page draws it
|
|
17
|
+
bunx mithaq generate messages # then fill every empty translation
|
|
18
|
+
bunx mithaq migrate --name <slug>
|
|
19
|
+
bunx mithaq generate --check
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
5. When `mithaq migrate` stops and asks for an answer in `mithaq.hints.json`, it is a rename or a drop. A drop deletes rows: ask the developer before you answer it.
|
|
23
|
+
6. From the project root, `bunx --package typescript tsc -p .` and the same with `-p` naming each app.
|
|
24
|
+
|
|
25
|
+
Commit the migration folder.
|
|
26
|
+
|
|
27
|
+
In a project made with `--layout single`, read each path as `AGENTS.md` maps it; the installed mithaq is `node_modules/mithaq/`.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: add-kayan
|
|
3
|
+
description: Add a kayan, one data type with its table, operations, access and admin pages, to this mithaq project. Use when asked for a new entity, table, resource or list in the dashboard.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Add a kayan
|
|
7
|
+
|
|
8
|
+
The steps are "Adding a kayan" in `AGENTS.md`, and the guide's worked example is "Add a kayan" in `README.md`. The installed mithaq is `packages/asas/node_modules/mithaq/`, or `node_modules/mithaq/` where the package manager hoists it to the root; its `docs/packages/mithaq/README.md` lists every kind and rule a field can take.
|
|
9
|
+
|
|
10
|
+
1. Ask, unless the request says: does each row belong to one organization (place `organization`, the usual answer) or does every organization share it?
|
|
11
|
+
2. Follow `AGENTS.md` "Adding a kayan", copying `packages/features/tags/`. Use only the kinds and rules the language holds; a new one changes the vocabulary, so stop and ask the developer.
|
|
12
|
+
3. Grant its keys to the roles that use it, as step 4 there says. A kayan no role is granted answers no one.
|
|
13
|
+
4. From `packages/asas/`, with `DATABASE_URL` pointing at a database built from the migrations (never a pushed one; `AGENTS.md` "Migrations" says how to build one):
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
bunx mithaq generate screens # when a screen draws it
|
|
17
|
+
bunx mithaq generate messages # then fill every empty translation
|
|
18
|
+
bunx mithaq migrate --name add_<name>
|
|
19
|
+
bunx mithaq generate --check
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
5. From the project root, `bunx --package typescript tsc -p .` and `bunx --package typescript tsc -p apps/asas-tanstack` (and `apps/asas-backoffice` when the project has it).
|
|
23
|
+
|
|
24
|
+
Commit the migration folder. Never edit a file whose first line reads ``// Written by `mithaq <command>` ``; run the command again.
|
|
25
|
+
|
|
26
|
+
In a project made with `--layout single`, read each path as `AGENTS.md` maps it; the installed mithaq is `node_modules/mithaq/`.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: eject-admin-piece
|
|
3
|
+
description: Change how the admin draws something in this mithaq project, by replacing a control, cell or node in the components map or by ejecting a mithaq-admin piece. Use when asked to restyle or change an admin control, list, form, shell or page piece.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Change an admin piece
|
|
7
|
+
|
|
8
|
+
The installed mithaq is `packages/asas/node_modules/mithaq/`, or `node_modules/mithaq/` where the package manager hoists it to the root. The guide is the admin's, its `docs/packages/mithaq-admin/README.md` ("Add or replace a control", "Replace a node", "Eject a piece"), and `eject` in its `docs/packages/mithaq/src/asas/cli/README.md`.
|
|
9
|
+
|
|
10
|
+
1. Reach for the components map first: a control, a cell or a node is replaced in the app's `src/components.ts` without ejecting anything.
|
|
11
|
+
2. Otherwise eject the piece, in the app that draws it (`apps/asas-tanstack` or `apps/asas-backoffice`):
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
bunx mithaq eject <item> # an unknown name lists every item
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
It writes the piece into `src/components/mithaq/`, drawn in place of the package's, and names any shadcn primitive or npm package to add. Restart the dev server.
|
|
18
|
+
3. Edit the ejected file in place; it is the project's now. Keep its last line, the `// mithaq-admin` marker, which `upgrade --check` reads.
|
|
19
|
+
4. Check, in the app:
|
|
20
|
+
|
|
21
|
+
```sh
|
|
22
|
+
bunx mithaq upgrade --check # the held files against the installed mithaq-admin
|
|
23
|
+
bunx --package typescript tsc -p .
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
To go back to the package's piece, delete the file, or run `bunx mithaq eject --prune`, which deletes every ejected file nobody edited.
|
|
27
|
+
|
|
28
|
+
In a project made with `--layout single`, read each path as `AGENTS.md` maps it; the installed mithaq is `node_modules/mithaq/`.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: upgrade-mithaq
|
|
3
|
+
description: Upgrade this project to a newer mithaq and mithaq-admin. Use when asked to update or upgrade mithaq, or when the installed version is behind the one a task needs.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Upgrade mithaq
|
|
7
|
+
|
|
8
|
+
Run each command from the project root. The installed mithaq, `$M` below, is `packages/asas/node_modules/mithaq/`, or `node_modules/mithaq/` where the package manager hoists it to the root, as in a project made with `--layout single`; each block finds it first.
|
|
9
|
+
|
|
10
|
+
1. Before you install, save the developer's own edits to the skills this version shipped. Skip this when `$M/skills` does not exist: that version shipped none.
|
|
11
|
+
|
|
12
|
+
```sh
|
|
13
|
+
M=packages/asas/node_modules/mithaq; [ -d "$M" ] || M=node_modules/mithaq
|
|
14
|
+
ls "$M/skills" > /tmp/mithaq-shipped-skills
|
|
15
|
+
for skill in $(cat /tmp/mithaq-shipped-skills); do diff -ru "$M/skills/$skill" ".claude/skills/$skill"; done > /tmp/mithaq-skill-edits.diff
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
2. Set `mithaq` and `mithaq-admin` to the same new version in every `package.json` that names them (`npm:@drhomet/mithaq@<version>` and `npm:@drhomet/mithaq-admin@<version>`), and install.
|
|
19
|
+
3. Read "Upgrading" in the new version's project guide, `$M/docs/templates/asas/README.md`: it says what a project made before each round changes. Apply every note for the rounds since this project's version, in order. A note that changes the vocabulary or drops data needs the developer's word first.
|
|
20
|
+
4. Replace the shipped skills with the new version's. A skill the old version shipped and the new one does not is deleted; a skill the developer wrote, which no version shipped, is left alone.
|
|
21
|
+
|
|
22
|
+
```sh
|
|
23
|
+
M=packages/asas/node_modules/mithaq; [ -d "$M" ] || M=node_modules/mithaq
|
|
24
|
+
for skill in $(cat /tmp/mithaq-shipped-skills 2>/dev/null); do rm -rf ".claude/skills/$skill"; done
|
|
25
|
+
mkdir -p .claude/skills && cp -R "$M/skills/." .claude/skills/
|
|
26
|
+
git status --short -- .claude/skills
|
|
27
|
+
git diff -- .claude/skills
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Then put back each of the developer's edits in `/tmp/mithaq-skill-edits.diff` that the new text lost, and ask the developer where an edit no longer fits the new text.
|
|
31
|
+
5. From `packages/asas/`, with `DATABASE_URL` exported, run `bunx mithaq generate --check`. It also checks the lock and the migrations; rerun `generate auth`, `screens` or `messages` as it says.
|
|
32
|
+
6. Run `bunx mithaq upgrade --check` in each folder holding a `components.json`: `packages/mithaq`, `apps/asas-tanstack` and, when the project has it, `apps/asas-backoffice`. Each file it reports as `differs` came from mithaq-admin: diff it against the package's and merge by hand, keeping the project's own edits.
|
|
33
|
+
7. From the project root, `bunx --package typescript tsc -p .` and the same with `-p` naming each app, then build and start each app once.
|
|
34
|
+
|
|
35
|
+
In a project made with `--layout single`, read each path as `AGENTS.md` maps it.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# The settings a development machine runs with; every variable is described in
|
|
2
|
+
# README.md, "Environment variables".
|
|
3
|
+
# create-mithaq writes a copy as `.env` here, in `apps/asas-tanstack` and in
|
|
4
|
+
# `apps/asas-backoffice`, with the same fresh secrets in each. The `seed` script
|
|
5
|
+
# and the apps' Vite read it, and `node --env-file=.env` does; the `mithaq`
|
|
6
|
+
# bin does not. A variable the shell already sets wins.
|
|
7
|
+
DATABASE_URL=postgres://postgres:postgres@localhost:5432/mithaq
|
|
8
|
+
# 32 characters at least. Unset, every POST under /api/auth/local answers 503.
|
|
9
|
+
LOCAL_AUTH_SECRET=
|
|
10
|
+
BETTER_AUTH_SECRET=
|
|
11
|
+
BETTER_AUTH_URL=http://localhost:5173
|
|
12
|
+
BACKOFFICE_URL=http://localhost:5174
|
|
13
|
+
# The account `bun run dev:setup` makes on a fresh database on this machine:
|
|
14
|
+
# the owner of an organization and, with the backoffice console, its super_admin.
|
|
15
|
+
# A development value only: dev:setup refuses any other database.
|
|
16
|
+
DEV_ADMIN_EMAIL=admin@example.com
|
|
17
|
+
DEV_ADMIN_PASSWORD=dev-admin-password
|
|
18
|
+
# The backoffice console's first administrator, and with one organization or
|
|
19
|
+
# none the app's first owner, are made only with this code, entered on
|
|
20
|
+
# /auth/create-first-user or /auth/first-run. Set a random value of 32
|
|
21
|
+
# characters or more before the first start outside development; a shorter
|
|
22
|
+
# one counts as unset. `vite dev` on this machine asks for none.
|
|
23
|
+
SETUP_CODE=
|
|
24
|
+
# The mailer: both, or neither. Without them a password reset is offered only
|
|
25
|
+
# in development, where the link is written to the server log, and an open
|
|
26
|
+
# sign-up refuses to start in production.
|
|
27
|
+
# RESEND_API_KEY=
|
|
28
|
+
# MAIL_FROM=Asas <mail@example.com>
|
|
29
|
+
# Required in production; development defaults them, the secret to a new
|
|
30
|
+
# random one on every start.
|
|
31
|
+
# STORAGE_SECRET=
|
|
32
|
+
# STORAGE_PREFIX=mithaq/asas
|
|
33
|
+
# STORAGE_ADAPTER=local
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# Working in a mithaq project
|
|
2
|
+
|
|
3
|
+
This project is built on mithaq. Each data type is a kayan (an entity), declared once with `defineKayan`; its table, input schema, operations, access and admin pages all follow from that one declaration. The arkan (singular rukn, a pillar) in the language, `packages/mithaq/src/mithaq.ts`, bring the kinds and rules a field can use. `buildAsas` in `packages/asas/src/asas.ts` builds the asas, the runtime that serves every kayan.
|
|
4
|
+
|
|
5
|
+
Run every `mithaq` command from `packages/asas/` unless it says otherwise. `README.md` beside this file is the full guide, with the steps and examples behind each section here. In a project made with `--layout single`, every folder below is one package: `packages/mithaq/src/` and `packages/asas/src/` are both `src/`, and `packages/features/<feature>/` is `src/features/<feature>/`.
|
|
6
|
+
|
|
7
|
+
The guides of the installed mithaq ship in its package, at their paths in the mithaq repository, under `node_modules/mithaq/docs/` (from `packages/asas/`, the nearest `node_modules` holding `mithaq`: its own or the root's). They match the installed version, so read them before GitHub, whose `main` describes the next release: `docs/packages/mithaq/README.md` is the language reference, `docs/packages/mithaq/src/asas/cli/README.md` the `mithaq` command, `docs/packages/mithaq/src/asas/runner/README.md` tenancy, `docs/packages/mithaq/src/drizzle/README.md` migrations in production and `docs/packages/mithaq-admin/README.md` the admin. The workflow skills in `.claude/skills/` (`add-kayan`, `add-field`, `eject-admin-piece`, `upgrade-mithaq`) are the ones the package ships under `skills/` at the version the project was made with; `upgrade-mithaq` copies them again.
|
|
8
|
+
|
|
9
|
+
## Where things go
|
|
10
|
+
|
|
11
|
+
The project is three steps, each named after what it holds, and each imports only the steps before it.
|
|
12
|
+
|
|
13
|
+
1. **The language**, `packages/mithaq` (`@asas/mithaq`). `src/mithaq.ts` declares it with `defineMithaq`, with its targets and screens, and exports `defineKayan`, `defineGlobal`, `buildAsas` and the tenant field `organization`. Beside it sits everything the language or more than one feature reads:
|
|
14
|
+
- `src/mithaq/auth/`: the Better Auth setup, imported as `@asas/mithaq/auth`.
|
|
15
|
+
- `src/mithaq/pages.ts`, with the rich-text add-on `rich-text-nodes.ts`, and with the audit-log add-on `audit-sink.ts`: the page trees every kayan page starts from, the rich-text nodes and the audit sink.
|
|
16
|
+
- `src/roles/`: `tenant-roles.ts`, the roles every organization gets and the permission keys each holds, and the access rows and grants beside it. Without the roles add-on those roles are Better Auth's own `owner`, `admin` and `member`, listed in `default-member-roles.ts`, and a member holds the ones its `member.role` names.
|
|
17
|
+
- `src/ui/`: the shells, layouts and pieces several screens draw.
|
|
18
|
+
- `src/steps/`, `src/mail/` and, with the uploads add-on, `src/storage/`: a write step, the mailers and storage adapters ejected from `mithaq-admin`, and the `index.ts` that chooses the mailer. They are this project's files.
|
|
19
|
+
2. **The features**, `packages/features/<feature>` (`@asas/<feature>`), each holding one or more kayan. `index.ts` exports the feature's `kayan` list (and `global`, for a single-row kayan). The media feature's `kayan` is a function of `reads`, what opens an image to an actor without `media.create`; a feature whose rows point at images exports its read (courses' `coverReads`), and the asas hands it in. Each kayan has a folder of its own, `<kayan>/<kayan>.ts`, with any page pieces only it draws in `<kayan>/ui/`; a child kayan is a sibling folder in its feature, never nested. `auth/user/` holds the Better Auth kayan, written by `mithaq generate auth`.
|
|
20
|
+
3. **The asas**, `packages/asas` (`asas`). `src/asas.ts` is the build: it spreads each feature's `kayan` into `buildAsas`. Beside it are each screen's own pieces (`src/ui-dashboard/`, `src/ui-portal/`, `src/ui-backoffice/`), `src/messages/` (one copy file per kayan, which `mithaq generate messages` fills with missing keys; translate in place), `src/migrations/` (written by `mithaq migrate`; commit them) and `src/seed.ts`.
|
|
21
|
+
|
|
22
|
+
A feature reaches another feature's kayan by its name (`relationTo: 'user'`) or through that feature's `index.ts`, never an inner file. The language never imports a feature or the asas.
|
|
23
|
+
|
|
24
|
+
`apps/asas-tanstack/` is the tenant app, serving `/dashboard` and `/portal`; `apps/asas-backoffice/`, with the backoffice add-on, is the backoffice console for staff across every organization. Both import the asas alone.
|
|
25
|
+
|
|
26
|
+
The project holds the add-ons it was made with (`roles`, `audit-log`, `settings`, `rich-text`, `uploads`, `media`, `courses`, `backoffice`); `packages/features/` and `apps/` show which. No command adds one yet: `README.md`, "Add an add-on", says how by hand.
|
|
27
|
+
|
|
28
|
+
## Adding a kayan
|
|
29
|
+
|
|
30
|
+
Copy `packages/features/tags/`; with the courses add-on, `packages/features/courses/courses/courses.ts` shows custom operations and steps.
|
|
31
|
+
|
|
32
|
+
1. Write `<name>/<name>.ts` in the feature it belongs to, or in a new feature `packages/features/<feature>/` with a `package.json` like `tags`' and an `index.ts`. Import `defineKayan` from `@asas/mithaq`. Spread `defaultFields` (id, createdAt, updatedAt) into `fields`, and `defaultOperations` into `targets.service.operations`, leaving out any operation the kayan should not have. Give every label and message one string per locale (`en` and `ar`).
|
|
33
|
+
2. Place `organization` in `fields` when each row belongs to one organization. Leave it out for a kayan every organization shares.
|
|
34
|
+
3. Add the kayan to its feature's `kayan` list. A new feature is a dependency of `packages/asas/package.json`, and its `kayan` is spread into `buildAsas` in `src/asas.ts`.
|
|
35
|
+
4. Grant its keys (`<name>.find`, `<name>.create`, `<name>.fields.<field>` and so on) to the roles that use it in `packages/mithaq/src/roles/tenant-roles.ts`, or under `member` in `default-member-roles.ts` in a project without the roles add-on, where `owner` and `admin` already hold every key.
|
|
36
|
+
5. To draw it, add it to a screen's `kayan` list in `packages/mithaq/src/mithaq.ts`, describe its pages under `targets.dashboard` in the kayan, and run `bunx mithaq generate screens`.
|
|
37
|
+
6. Run `bunx mithaq generate messages` and fill any empty translation it adds.
|
|
38
|
+
7. Write the migration: `bunx mithaq migrate --name add_<name>`. Commit the folder it writes.
|
|
39
|
+
8. Run `bunx mithaq generate --check`.
|
|
40
|
+
|
|
41
|
+
## The tenant field
|
|
42
|
+
|
|
43
|
+
A kayan that places `organization` is per-organization, and mithaq core enforces it on every managed read and write; nothing in the project can turn it off. The scope is the signed-in session's verified active organization. A create fills `organization` from the session, so a caller or a step never sets it, and it never changes. Another organization's row answers like a missing one. Raw SQL through `ctx.tx` is not scoped: filter by organization there yourself. Write the field as `organization` from `@asas/mithaq`; a look-alike field that is not bound is refused.
|
|
44
|
+
|
|
45
|
+
On a per-organization kayan, `rules: { unique: true }` means unique within each organization, and `{ within: 'organization', unique: [...], index: [...] }` in `indexes` builds indexes led by the organization. A plain `{ fields, unique: true }` entry is unique across every organization.
|
|
46
|
+
|
|
47
|
+
How many organizations the project holds, and who may sign up and join, is `packages/mithaq/src/mithaq/auth/organizations.ts` (`organizations`, `showOrganization`, `signUp`, `joinRole`, `verifyEmail`, `allowedDomains`). In one organization the field and the scope are the same, so keep placing `organization` on every per-organization kayan: leaving it off makes the kayan shared by every organization the day the project holds many. README.md, "Organization modes", says what each value does and how to change it.
|
|
48
|
+
|
|
49
|
+
Reads that reach further (`tenant: 'mine' | 'all'`), what is refused, and the index rules are in the tenancy guide, `docs/packages/mithaq/src/asas/runner/README.md` in the installed mithaq.
|
|
50
|
+
|
|
51
|
+
## Migrations
|
|
52
|
+
|
|
53
|
+
- In development `asas.connect()` pushes the schema; nothing needs a migration to run locally.
|
|
54
|
+
- A project made without every add-on that holds tables starts with no migration: write its first, `bunx mithaq migrate --name init`, against an empty database before it first deploys.
|
|
55
|
+
- `mithaq migrate` refuses to write against a pushed database. Point `DATABASE_URL` at a database built from the migrations: create an empty one, apply them with the `drizzle-kit` the installed mithaq depends on, then run `bunx mithaq migrate --name <slug>`. The slug is lowercase letters, digits and underscores.
|
|
56
|
+
|
|
57
|
+
```sh
|
|
58
|
+
DRIZZLE_KIT=$(node -p "path.join(path.dirname(require('module').createRequire(fs.realpathSync('node_modules/mithaq/package.json')).resolve('drizzle-kit')), 'bin.cjs')")
|
|
59
|
+
node "$DRIZZLE_KIT" migrate --config src/migrations/drizzle.config.ts
|
|
60
|
+
```
|
|
61
|
+
- When a change would lose data, `mithaq migrate` stops and asks for an answer in `mithaq.hints.json`. A drop deletes rows: ask the developer before you write one.
|
|
62
|
+
- In production `connect()` checks for pending migrations, as `prodMigrations` in `packages/mithaq/src/mithaq.ts` says: `pending: 'refuse'` refuses to start, `pending: 'run'` applies them under a lock. `drizzle-kit migrate` run by hand takes no lock, so never run it while an app is starting. See `README.md`, "Running in production", and the guide to migrations in production, `docs/packages/mithaq/src/drizzle/README.md` in the installed mithaq.
|
|
63
|
+
|
|
64
|
+
## Rules
|
|
65
|
+
|
|
66
|
+
- The vocabulary of `defineMithaq` in `packages/mithaq/src/mithaq.ts` (its locales, kinds, rules, target names and capabilities, and root keys) changes only when the developer asks for that change. When a task needs it, tell the developer what and why first. If the project has a `mithaq.lock`, `mithaq lock` shows a popup the developer approves; never edit the lock by hand. Everything in `defineKayan`, `defineGlobal` and `buildAsas` is yours to change. With a lock, `bunx mithaq lock --check`, part of `bunx mithaq generate --check`, fails on a word the lock does not record.
|
|
67
|
+
- The backoffice is served on a subdomain of its own (`backoffice.example.com` beside `app.example.com`), never mounted under a path of the customer app: browsers isolate scripts by origin and send cookies by host, so on one host a script flaw in the customer app would reach staff sessions. Start refuses when `BACKOFFICE_URL` and `BETTER_AUTH_URL` share an origin, or a host off this machine. The backoffice's Origin checks are the barrier between the two subdomains: keep one on every route that changes state. `README.md`, "Deploying both apps on one domain", shows the proxy. The start's refusal checks the first; review checks the Origin checks.
|
|
68
|
+
- A file whose first line reads ``// Written by `mithaq <command>` `` is regenerated by that command, never edited. `bunx mithaq generate --check` fails when one differs from what its command writes.
|
|
69
|
+
- The admin's pieces come from the `mithaq-admin` package. Replace a control, cell or node in the components map (`src/components.ts` in each app); to change another piece, `bunx mithaq eject <item>` in the app writes it into `src/components/mithaq/`, drawn in place of the package's. A file ejected from `mithaq-admin` ends with a `// mithaq-admin` marker line. It is this project's: edit it in place. After you update mithaq and mithaq-admin together, `bunx mithaq upgrade --check` names each file that differs; merge an edited one by hand.
|
|
70
|
+
- A function the project writes takes one object once it has three or more parameters. Steps keep `(ctx, tools)`. Review checks this.
|
|
71
|
+
- Comments say why, never what. Review checks this.
|
|
72
|
+
|
|
73
|
+
## Commands
|
|
74
|
+
|
|
75
|
+
The `mithaq` bin runs under Node and does not read `.env`, so export `DATABASE_URL` first. Commands that touch the database refuse to run without it.
|
|
76
|
+
|
|
77
|
+
```sh
|
|
78
|
+
bunx mithaq --help
|
|
79
|
+
bunx mithaq generate --check # the lock, generated files, migrations and copies; writes nothing
|
|
80
|
+
bunx mithaq generate auth # the Better Auth kayan
|
|
81
|
+
bunx mithaq generate messages # copy files
|
|
82
|
+
bunx mithaq generate screens # each screen's routes in the apps
|
|
83
|
+
bunx mithaq migrate --name <slug>
|
|
84
|
+
bunx mithaq migrate --check
|
|
85
|
+
bunx mithaq lock --check
|
|
86
|
+
bunx mithaq upgrade --check
|
|
87
|
+
bun run dev:setup --seed # a fresh dev database: the schema, the dev admin .env names, sample rows
|
|
88
|
+
bun run seed
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
From the project root, where an isolated install puts no `typescript` and a bare `bunx tsc` would fetch the unrelated `tsc` package:
|
|
92
|
+
|
|
93
|
+
```sh
|
|
94
|
+
bunx --package typescript tsc -p .
|
|
95
|
+
bunx --package typescript tsc -p apps/asas-tanstack
|
|
96
|
+
bunx --package typescript tsc -p apps/asas-backoffice
|
|
97
|
+
bun run --cwd apps/asas-tanstack dev # http://localhost:5173
|
|
98
|
+
bun run --cwd apps/asas-backoffice dev # http://localhost:5174
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
`README.md` beside this file is the guide to this project. The language reference is `docs/packages/mithaq/README.md` in the installed mithaq.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@AGENTS.md
|