@cherishxn/agent-scaffold 0.0.0-stage → 1.0.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 +21 -0
- package/README.md +71 -2
- package/THIRD_PARTY_NOTICES.md +14 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +100 -0
- package/dist/generate.d.ts +55 -0
- package/dist/generate.js +154 -0
- package/dist/model.d.ts +33 -0
- package/dist/model.js +24 -0
- package/dist/verify.d.ts +61 -0
- package/dist/verify.js +264 -0
- package/package.json +49 -4
- package/schemas/manifest.json +171 -0
- package/schemas/plan.json +164 -0
- package/schemas/result.json +97 -0
- package/schemas/spec.json +50 -0
- package/skills/scaffold-use/SKILL.md +6 -0
- package/templates/catalog.json +37 -0
- package/templates/next-fullstack-antd/.agents/skills/design-contract/SKILL.md +23 -0
- package/templates/next-fullstack-antd/.agents/skills/project-work/SKILL.md +8 -0
- package/templates/next-fullstack-antd/.claude/skills/design-contract/SKILL.md +23 -0
- package/templates/next-fullstack-antd/.claude/skills/project-work/SKILL.md +8 -0
- package/templates/next-fullstack-antd/.dockerignore +18 -0
- package/templates/next-fullstack-antd/.env.example +13 -0
- package/templates/next-fullstack-antd/.grok/skills/design-contract/SKILL.md +23 -0
- package/templates/next-fullstack-antd/.grok/skills/project-work/SKILL.md +8 -0
- package/templates/next-fullstack-antd/.scaffold-checks.json +7 -0
- package/templates/next-fullstack-antd/AGENTS.md +11 -0
- package/templates/next-fullstack-antd/CLAUDE.md +1 -0
- package/templates/next-fullstack-antd/DESIGN.md +208 -0
- package/templates/next-fullstack-antd/LICENSE +21 -0
- package/templates/next-fullstack-antd/README.md +55 -0
- package/templates/next-fullstack-antd/THIRD_PARTY_NOTICES.md +14 -0
- package/templates/next-fullstack-antd/compose.yaml +18 -0
- package/templates/next-fullstack-antd/design/guide.md +61 -0
- package/templates/next-fullstack-antd/design/layout.css +6 -0
- package/templates/next-fullstack-antd/design/structure.json +107 -0
- package/templates/next-fullstack-antd/design/tokens.json +171 -0
- package/templates/next-fullstack-antd/design/widgets.css +30 -0
- package/templates/next-fullstack-antd/design/widgets.json +233 -0
- package/templates/next-fullstack-antd/docs/PROJECT.md +9 -0
- package/templates/next-fullstack-antd/docs/api.d.ts +516 -0
- package/templates/next-fullstack-antd/docs/openapi.json +439 -0
- package/templates/next-fullstack-antd/gitignore.template +19 -0
- package/templates/next-fullstack-antd/licenses/fastapi.txt +21 -0
- package/templates/next-fullstack-antd/licenses/nest.txt +22 -0
- package/templates/next-fullstack-antd/licenses/next.txt +21 -0
- package/templates/next-fullstack-antd/licenses/shadcn.txt +21 -0
- package/templates/next-fullstack-antd/licenses/sources.json +27 -0
- package/templates/next-fullstack-antd/licenses/spring.txt +202 -0
- package/templates/next-fullstack-antd/package-lock.json +440 -0
- package/templates/next-fullstack-antd/package.json +21 -0
- package/templates/next-fullstack-antd/playwright.config.ts +3 -0
- package/templates/next-fullstack-antd/project.json +8 -0
- package/templates/next-fullstack-antd/scripts/design-coverage.mjs +20 -0
- package/templates/next-fullstack-antd/scripts/design-next-cleanup.mjs +13 -0
- package/templates/next-fullstack-antd/scripts/design-verify.mjs +154 -0
- package/templates/next-fullstack-antd/scripts/design.mjs +108 -0
- package/templates/next-fullstack-antd/scripts/project.mjs +118 -0
- package/templates/next-fullstack-antd/tests/contract.spec.ts +47 -0
- package/templates/next-fullstack-antd/tests/design/harness.tsx +63 -0
- package/templates/next-fullstack-antd/tests/ui.spec.ts +61 -0
- package/templates/next-fullstack-antd/web/Dockerfile +12 -0
- package/templates/next-fullstack-antd/web/app/api/auth/login/route.ts +1 -0
- package/templates/next-fullstack-antd/web/app/api/auth/logout/route.ts +1 -0
- package/templates/next-fullstack-antd/web/app/api/auth/me/route.ts +1 -0
- package/templates/next-fullstack-antd/web/app/api/health/route.ts +1 -0
- package/templates/next-fullstack-antd/web/app/api/records/[id]/route.ts +5 -0
- package/templates/next-fullstack-antd/web/app/api/records/route.ts +3 -0
- package/templates/next-fullstack-antd/web/app/layout.tsx +5 -0
- package/templates/next-fullstack-antd/web/app/page.tsx +2 -0
- package/templates/next-fullstack-antd/web/eslint.config.mjs +3 -0
- package/templates/next-fullstack-antd/web/lib/api.ts +35 -0
- package/templates/next-fullstack-antd/web/lib/auth.ts +10 -0
- package/templates/next-fullstack-antd/web/lib/db.ts +3 -0
- package/templates/next-fullstack-antd/web/lib/session.test.ts +15 -0
- package/templates/next-fullstack-antd/web/lib/validation.test.ts +3 -0
- package/templates/next-fullstack-antd/web/lib/validation.ts +5 -0
- package/templates/next-fullstack-antd/web/next-env.d.ts +7 -0
- package/templates/next-fullstack-antd/web/next.config.ts +3 -0
- package/templates/next-fullstack-antd/web/package.json +35 -0
- package/templates/next-fullstack-antd/web/pnpm-lock.yaml +3756 -0
- package/templates/next-fullstack-antd/web/pnpm-workspace.yaml +7 -0
- package/templates/next-fullstack-antd/web/prisma/migrations/202610190001_initial/migration.sql +99 -0
- package/templates/next-fullstack-antd/web/prisma/migrations/migration_lock.toml +1 -0
- package/templates/next-fullstack-antd/web/prisma/schema.prisma +72 -0
- package/templates/next-fullstack-antd/web/scripts/seed.ts +4 -0
- package/templates/next-fullstack-antd/web/src/App.tsx +29 -0
- package/templates/next-fullstack-antd/web/src/design-layout.css +7 -0
- package/templates/next-fullstack-antd/web/src/design-runtime.json +511 -0
- package/templates/next-fullstack-antd/web/src/design-tokens.css +168 -0
- package/templates/next-fullstack-antd/web/src/design-widgets.css +31 -0
- package/templates/next-fullstack-antd/web/src/structure-view.tsx +16 -0
- package/templates/next-fullstack-antd/web/src/styles.css +3 -0
- package/templates/next-fullstack-antd/web/src/ui.tsx +30 -0
- package/templates/next-fullstack-antd/web/src/widget-icon.tsx +5 -0
- package/templates/next-fullstack-antd/web/src/widget-types.ts +13 -0
- package/templates/next-fullstack-antd/web/src/workspace-model.ts +85 -0
- package/templates/next-fullstack-antd/web/tsconfig.json +42 -0
- package/templates/next-fullstack-antd/web/vitest.config.ts +2 -0
- package/templates/next-fullstack-shadcn/.agents/skills/design-contract/SKILL.md +23 -0
- package/templates/next-fullstack-shadcn/.agents/skills/project-work/SKILL.md +8 -0
- package/templates/next-fullstack-shadcn/.claude/skills/design-contract/SKILL.md +23 -0
- package/templates/next-fullstack-shadcn/.claude/skills/project-work/SKILL.md +8 -0
- package/templates/next-fullstack-shadcn/.dockerignore +18 -0
- package/templates/next-fullstack-shadcn/.env.example +13 -0
- package/templates/next-fullstack-shadcn/.grok/skills/design-contract/SKILL.md +23 -0
- package/templates/next-fullstack-shadcn/.grok/skills/project-work/SKILL.md +8 -0
- package/templates/next-fullstack-shadcn/.scaffold-checks.json +7 -0
- package/templates/next-fullstack-shadcn/AGENTS.md +11 -0
- package/templates/next-fullstack-shadcn/CLAUDE.md +1 -0
- package/templates/next-fullstack-shadcn/DESIGN.md +208 -0
- package/templates/next-fullstack-shadcn/LICENSE +21 -0
- package/templates/next-fullstack-shadcn/README.md +55 -0
- package/templates/next-fullstack-shadcn/THIRD_PARTY_NOTICES.md +14 -0
- package/templates/next-fullstack-shadcn/compose.yaml +18 -0
- package/templates/next-fullstack-shadcn/design/guide.md +61 -0
- package/templates/next-fullstack-shadcn/design/layout.css +6 -0
- package/templates/next-fullstack-shadcn/design/structure.json +107 -0
- package/templates/next-fullstack-shadcn/design/tokens.json +171 -0
- package/templates/next-fullstack-shadcn/design/widgets.css +30 -0
- package/templates/next-fullstack-shadcn/design/widgets.json +233 -0
- package/templates/next-fullstack-shadcn/docs/PROJECT.md +9 -0
- package/templates/next-fullstack-shadcn/docs/api.d.ts +516 -0
- package/templates/next-fullstack-shadcn/docs/openapi.json +439 -0
- package/templates/next-fullstack-shadcn/gitignore.template +19 -0
- package/templates/next-fullstack-shadcn/licenses/fastapi.txt +21 -0
- package/templates/next-fullstack-shadcn/licenses/nest.txt +22 -0
- package/templates/next-fullstack-shadcn/licenses/next.txt +21 -0
- package/templates/next-fullstack-shadcn/licenses/shadcn.txt +21 -0
- package/templates/next-fullstack-shadcn/licenses/sources.json +27 -0
- package/templates/next-fullstack-shadcn/licenses/spring.txt +202 -0
- package/templates/next-fullstack-shadcn/package-lock.json +440 -0
- package/templates/next-fullstack-shadcn/package.json +21 -0
- package/templates/next-fullstack-shadcn/playwright.config.ts +3 -0
- package/templates/next-fullstack-shadcn/project.json +8 -0
- package/templates/next-fullstack-shadcn/scripts/design-coverage.mjs +20 -0
- package/templates/next-fullstack-shadcn/scripts/design-next-cleanup.mjs +13 -0
- package/templates/next-fullstack-shadcn/scripts/design-verify.mjs +154 -0
- package/templates/next-fullstack-shadcn/scripts/design.mjs +108 -0
- package/templates/next-fullstack-shadcn/scripts/project.mjs +118 -0
- package/templates/next-fullstack-shadcn/tests/contract.spec.ts +47 -0
- package/templates/next-fullstack-shadcn/tests/design/harness.tsx +63 -0
- package/templates/next-fullstack-shadcn/tests/ui.spec.ts +61 -0
- package/templates/next-fullstack-shadcn/web/Dockerfile +12 -0
- package/templates/next-fullstack-shadcn/web/app/api/auth/login/route.ts +1 -0
- package/templates/next-fullstack-shadcn/web/app/api/auth/logout/route.ts +1 -0
- package/templates/next-fullstack-shadcn/web/app/api/auth/me/route.ts +1 -0
- package/templates/next-fullstack-shadcn/web/app/api/health/route.ts +1 -0
- package/templates/next-fullstack-shadcn/web/app/api/records/[id]/route.ts +5 -0
- package/templates/next-fullstack-shadcn/web/app/api/records/route.ts +3 -0
- package/templates/next-fullstack-shadcn/web/app/layout.tsx +4 -0
- package/templates/next-fullstack-shadcn/web/app/page.tsx +2 -0
- package/templates/next-fullstack-shadcn/web/eslint.config.mjs +3 -0
- package/templates/next-fullstack-shadcn/web/lib/api.ts +35 -0
- package/templates/next-fullstack-shadcn/web/lib/auth.ts +10 -0
- package/templates/next-fullstack-shadcn/web/lib/db.ts +3 -0
- package/templates/next-fullstack-shadcn/web/lib/session.test.ts +15 -0
- package/templates/next-fullstack-shadcn/web/lib/validation.test.ts +3 -0
- package/templates/next-fullstack-shadcn/web/lib/validation.ts +5 -0
- package/templates/next-fullstack-shadcn/web/next-env.d.ts +7 -0
- package/templates/next-fullstack-shadcn/web/next.config.ts +3 -0
- package/templates/next-fullstack-shadcn/web/package.json +39 -0
- package/templates/next-fullstack-shadcn/web/pnpm-lock.yaml +3286 -0
- package/templates/next-fullstack-shadcn/web/pnpm-workspace.yaml +7 -0
- package/templates/next-fullstack-shadcn/web/postcss.config.mjs +1 -0
- package/templates/next-fullstack-shadcn/web/prisma/migrations/202610190001_initial/migration.sql +99 -0
- package/templates/next-fullstack-shadcn/web/prisma/migrations/migration_lock.toml +1 -0
- package/templates/next-fullstack-shadcn/web/prisma/schema.prisma +72 -0
- package/templates/next-fullstack-shadcn/web/scripts/seed.ts +4 -0
- package/templates/next-fullstack-shadcn/web/src/App.tsx +30 -0
- package/templates/next-fullstack-shadcn/web/src/design-layout.css +7 -0
- package/templates/next-fullstack-shadcn/web/src/design-runtime.json +511 -0
- package/templates/next-fullstack-shadcn/web/src/design-tokens.css +168 -0
- package/templates/next-fullstack-shadcn/web/src/design-widgets.css +31 -0
- package/templates/next-fullstack-shadcn/web/src/structure-view.tsx +16 -0
- package/templates/next-fullstack-shadcn/web/src/styles.css +3 -0
- package/templates/next-fullstack-shadcn/web/src/tailwind.css +2 -0
- package/templates/next-fullstack-shadcn/web/src/ui.tsx +13 -0
- package/templates/next-fullstack-shadcn/web/src/widget-icon.tsx +5 -0
- package/templates/next-fullstack-shadcn/web/src/widget-types.ts +13 -0
- package/templates/next-fullstack-shadcn/web/src/workspace-model.ts +85 -0
- package/templates/next-fullstack-shadcn/web/tsconfig.json +42 -0
- package/templates/next-fullstack-shadcn/web/vitest.config.ts +2 -0
- package/templates/react-fastapi-antd/.agents/skills/design-contract/SKILL.md +23 -0
- package/templates/react-fastapi-antd/.agents/skills/project-work/SKILL.md +8 -0
- package/templates/react-fastapi-antd/.claude/skills/design-contract/SKILL.md +23 -0
- package/templates/react-fastapi-antd/.claude/skills/project-work/SKILL.md +8 -0
- package/templates/react-fastapi-antd/.dockerignore +18 -0
- package/templates/react-fastapi-antd/.env.example +13 -0
- package/templates/react-fastapi-antd/.grok/skills/design-contract/SKILL.md +23 -0
- package/templates/react-fastapi-antd/.grok/skills/project-work/SKILL.md +8 -0
- package/templates/react-fastapi-antd/.scaffold-checks.json +7 -0
- package/templates/react-fastapi-antd/AGENTS.md +11 -0
- package/templates/react-fastapi-antd/CLAUDE.md +1 -0
- package/templates/react-fastapi-antd/DESIGN.md +208 -0
- package/templates/react-fastapi-antd/LICENSE +21 -0
- package/templates/react-fastapi-antd/README.md +55 -0
- package/templates/react-fastapi-antd/THIRD_PARTY_NOTICES.md +14 -0
- package/templates/react-fastapi-antd/backend/.python-version +1 -0
- package/templates/react-fastapi-antd/backend/Dockerfile +10 -0
- package/templates/react-fastapi-antd/backend/alembic.ini +3 -0
- package/templates/react-fastapi-antd/backend/app/__init__.py +0 -0
- package/templates/react-fastapi-antd/backend/app/core/__init__.py +0 -0
- package/templates/react-fastapi-antd/backend/app/core/security.py +25 -0
- package/templates/react-fastapi-antd/backend/app/db.py +11 -0
- package/templates/react-fastapi-antd/backend/app/main.py +146 -0
- package/templates/react-fastapi-antd/backend/app/models.py +21 -0
- package/templates/react-fastapi-antd/backend/app/seed.py +21 -0
- package/templates/react-fastapi-antd/backend/migrations/env.py +9 -0
- package/templates/react-fastapi-antd/backend/migrations/versions/0001_initial.py +18 -0
- package/templates/react-fastapi-antd/backend/pyproject.toml +16 -0
- package/templates/react-fastapi-antd/backend/tests/test_api.py +27 -0
- package/templates/react-fastapi-antd/backend/uv.lock +1085 -0
- package/templates/react-fastapi-antd/compose.yaml +18 -0
- package/templates/react-fastapi-antd/design/guide.md +61 -0
- package/templates/react-fastapi-antd/design/layout.css +6 -0
- package/templates/react-fastapi-antd/design/structure.json +107 -0
- package/templates/react-fastapi-antd/design/tokens.json +171 -0
- package/templates/react-fastapi-antd/design/widgets.css +30 -0
- package/templates/react-fastapi-antd/design/widgets.json +233 -0
- package/templates/react-fastapi-antd/docs/PROJECT.md +9 -0
- package/templates/react-fastapi-antd/docs/api.d.ts +516 -0
- package/templates/react-fastapi-antd/docs/openapi.json +439 -0
- package/templates/react-fastapi-antd/gitignore.template +19 -0
- package/templates/react-fastapi-antd/licenses/fastapi.txt +21 -0
- package/templates/react-fastapi-antd/licenses/nest.txt +22 -0
- package/templates/react-fastapi-antd/licenses/next.txt +21 -0
- package/templates/react-fastapi-antd/licenses/shadcn.txt +21 -0
- package/templates/react-fastapi-antd/licenses/sources.json +27 -0
- package/templates/react-fastapi-antd/licenses/spring.txt +202 -0
- package/templates/react-fastapi-antd/package-lock.json +440 -0
- package/templates/react-fastapi-antd/package.json +21 -0
- package/templates/react-fastapi-antd/playwright.config.ts +3 -0
- package/templates/react-fastapi-antd/project.json +8 -0
- package/templates/react-fastapi-antd/scripts/design-coverage.mjs +20 -0
- package/templates/react-fastapi-antd/scripts/design-next-cleanup.mjs +13 -0
- package/templates/react-fastapi-antd/scripts/design-verify.mjs +154 -0
- package/templates/react-fastapi-antd/scripts/design.mjs +108 -0
- package/templates/react-fastapi-antd/scripts/project.mjs +118 -0
- package/templates/react-fastapi-antd/tests/contract.spec.ts +47 -0
- package/templates/react-fastapi-antd/tests/design/harness.tsx +63 -0
- package/templates/react-fastapi-antd/tests/ui.spec.ts +61 -0
- package/templates/react-fastapi-antd/web/bun.lock +442 -0
- package/templates/react-fastapi-antd/web/eslint.config.mjs +3 -0
- package/templates/react-fastapi-antd/web/index.html +1 -0
- package/templates/react-fastapi-antd/web/package.json +28 -0
- package/templates/react-fastapi-antd/web/src/App.tsx +29 -0
- package/templates/react-fastapi-antd/web/src/design-layout.css +7 -0
- package/templates/react-fastapi-antd/web/src/design-runtime.json +511 -0
- package/templates/react-fastapi-antd/web/src/design-tokens.css +168 -0
- package/templates/react-fastapi-antd/web/src/design-widgets.css +31 -0
- package/templates/react-fastapi-antd/web/src/main.tsx +6 -0
- package/templates/react-fastapi-antd/web/src/structure-view.tsx +16 -0
- package/templates/react-fastapi-antd/web/src/styles.css +3 -0
- package/templates/react-fastapi-antd/web/src/ui.tsx +30 -0
- package/templates/react-fastapi-antd/web/src/widget-icon.tsx +5 -0
- package/templates/react-fastapi-antd/web/src/widget-types.ts +13 -0
- package/templates/react-fastapi-antd/web/src/workspace-model.ts +85 -0
- package/templates/react-fastapi-antd/web/tsconfig.json +22 -0
- package/templates/react-fastapi-antd/web/vite.config.ts +3 -0
- package/templates/react-fastapi-shadcn/.agents/skills/design-contract/SKILL.md +23 -0
- package/templates/react-fastapi-shadcn/.agents/skills/project-work/SKILL.md +8 -0
- package/templates/react-fastapi-shadcn/.claude/skills/design-contract/SKILL.md +23 -0
- package/templates/react-fastapi-shadcn/.claude/skills/project-work/SKILL.md +8 -0
- package/templates/react-fastapi-shadcn/.dockerignore +18 -0
- package/templates/react-fastapi-shadcn/.env.example +13 -0
- package/templates/react-fastapi-shadcn/.grok/skills/design-contract/SKILL.md +23 -0
- package/templates/react-fastapi-shadcn/.grok/skills/project-work/SKILL.md +8 -0
- package/templates/react-fastapi-shadcn/.scaffold-checks.json +7 -0
- package/templates/react-fastapi-shadcn/AGENTS.md +11 -0
- package/templates/react-fastapi-shadcn/CLAUDE.md +1 -0
- package/templates/react-fastapi-shadcn/DESIGN.md +208 -0
- package/templates/react-fastapi-shadcn/LICENSE +21 -0
- package/templates/react-fastapi-shadcn/README.md +55 -0
- package/templates/react-fastapi-shadcn/THIRD_PARTY_NOTICES.md +14 -0
- package/templates/react-fastapi-shadcn/backend/.python-version +1 -0
- package/templates/react-fastapi-shadcn/backend/Dockerfile +10 -0
- package/templates/react-fastapi-shadcn/backend/alembic.ini +3 -0
- package/templates/react-fastapi-shadcn/backend/app/__init__.py +0 -0
- package/templates/react-fastapi-shadcn/backend/app/core/__init__.py +0 -0
- package/templates/react-fastapi-shadcn/backend/app/core/security.py +25 -0
- package/templates/react-fastapi-shadcn/backend/app/db.py +11 -0
- package/templates/react-fastapi-shadcn/backend/app/main.py +146 -0
- package/templates/react-fastapi-shadcn/backend/app/models.py +21 -0
- package/templates/react-fastapi-shadcn/backend/app/seed.py +21 -0
- package/templates/react-fastapi-shadcn/backend/migrations/env.py +9 -0
- package/templates/react-fastapi-shadcn/backend/migrations/versions/0001_initial.py +18 -0
- package/templates/react-fastapi-shadcn/backend/pyproject.toml +16 -0
- package/templates/react-fastapi-shadcn/backend/tests/test_api.py +27 -0
- package/templates/react-fastapi-shadcn/backend/uv.lock +1085 -0
- package/templates/react-fastapi-shadcn/compose.yaml +18 -0
- package/templates/react-fastapi-shadcn/design/guide.md +61 -0
- package/templates/react-fastapi-shadcn/design/layout.css +6 -0
- package/templates/react-fastapi-shadcn/design/structure.json +107 -0
- package/templates/react-fastapi-shadcn/design/tokens.json +171 -0
- package/templates/react-fastapi-shadcn/design/widgets.css +30 -0
- package/templates/react-fastapi-shadcn/design/widgets.json +233 -0
- package/templates/react-fastapi-shadcn/docs/PROJECT.md +9 -0
- package/templates/react-fastapi-shadcn/docs/api.d.ts +516 -0
- package/templates/react-fastapi-shadcn/docs/openapi.json +439 -0
- package/templates/react-fastapi-shadcn/gitignore.template +19 -0
- package/templates/react-fastapi-shadcn/licenses/fastapi.txt +21 -0
- package/templates/react-fastapi-shadcn/licenses/nest.txt +22 -0
- package/templates/react-fastapi-shadcn/licenses/next.txt +21 -0
- package/templates/react-fastapi-shadcn/licenses/shadcn.txt +21 -0
- package/templates/react-fastapi-shadcn/licenses/sources.json +27 -0
- package/templates/react-fastapi-shadcn/licenses/spring.txt +202 -0
- package/templates/react-fastapi-shadcn/package-lock.json +440 -0
- package/templates/react-fastapi-shadcn/package.json +21 -0
- package/templates/react-fastapi-shadcn/playwright.config.ts +3 -0
- package/templates/react-fastapi-shadcn/project.json +8 -0
- package/templates/react-fastapi-shadcn/scripts/design-coverage.mjs +20 -0
- package/templates/react-fastapi-shadcn/scripts/design-next-cleanup.mjs +13 -0
- package/templates/react-fastapi-shadcn/scripts/design-verify.mjs +154 -0
- package/templates/react-fastapi-shadcn/scripts/design.mjs +108 -0
- package/templates/react-fastapi-shadcn/scripts/project.mjs +118 -0
- package/templates/react-fastapi-shadcn/tests/contract.spec.ts +47 -0
- package/templates/react-fastapi-shadcn/tests/design/harness.tsx +63 -0
- package/templates/react-fastapi-shadcn/tests/ui.spec.ts +61 -0
- package/templates/react-fastapi-shadcn/web/bun.lock +413 -0
- package/templates/react-fastapi-shadcn/web/eslint.config.mjs +3 -0
- package/templates/react-fastapi-shadcn/web/index.html +1 -0
- package/templates/react-fastapi-shadcn/web/package.json +33 -0
- package/templates/react-fastapi-shadcn/web/src/App.tsx +30 -0
- package/templates/react-fastapi-shadcn/web/src/design-layout.css +7 -0
- package/templates/react-fastapi-shadcn/web/src/design-runtime.json +511 -0
- package/templates/react-fastapi-shadcn/web/src/design-tokens.css +168 -0
- package/templates/react-fastapi-shadcn/web/src/design-widgets.css +31 -0
- package/templates/react-fastapi-shadcn/web/src/main.tsx +6 -0
- package/templates/react-fastapi-shadcn/web/src/structure-view.tsx +16 -0
- package/templates/react-fastapi-shadcn/web/src/styles.css +3 -0
- package/templates/react-fastapi-shadcn/web/src/tailwind.css +2 -0
- package/templates/react-fastapi-shadcn/web/src/ui.tsx +13 -0
- package/templates/react-fastapi-shadcn/web/src/widget-icon.tsx +5 -0
- package/templates/react-fastapi-shadcn/web/src/widget-types.ts +13 -0
- package/templates/react-fastapi-shadcn/web/src/workspace-model.ts +85 -0
- package/templates/react-fastapi-shadcn/web/tsconfig.json +22 -0
- package/templates/react-fastapi-shadcn/web/vite.config.ts +4 -0
- package/templates/react-nest-antd/.agents/skills/design-contract/SKILL.md +23 -0
- package/templates/react-nest-antd/.agents/skills/project-work/SKILL.md +8 -0
- package/templates/react-nest-antd/.claude/skills/design-contract/SKILL.md +23 -0
- package/templates/react-nest-antd/.claude/skills/project-work/SKILL.md +8 -0
- package/templates/react-nest-antd/.dockerignore +18 -0
- package/templates/react-nest-antd/.env.example +13 -0
- package/templates/react-nest-antd/.grok/skills/design-contract/SKILL.md +23 -0
- package/templates/react-nest-antd/.grok/skills/project-work/SKILL.md +8 -0
- package/templates/react-nest-antd/.scaffold-checks.json +7 -0
- package/templates/react-nest-antd/AGENTS.md +11 -0
- package/templates/react-nest-antd/CLAUDE.md +1 -0
- package/templates/react-nest-antd/DESIGN.md +208 -0
- package/templates/react-nest-antd/LICENSE +21 -0
- package/templates/react-nest-antd/README.md +55 -0
- package/templates/react-nest-antd/THIRD_PARTY_NOTICES.md +14 -0
- package/templates/react-nest-antd/backend/Dockerfile +12 -0
- package/templates/react-nest-antd/backend/eslint.config.mjs +3 -0
- package/templates/react-nest-antd/backend/jest.config.cjs +1 -0
- package/templates/react-nest-antd/backend/package.json +40 -0
- package/templates/react-nest-antd/backend/pnpm-lock.yaml +5165 -0
- package/templates/react-nest-antd/backend/pnpm-workspace.yaml +6 -0
- package/templates/react-nest-antd/backend/prisma/migrations/202610190001_initial/migration.sql +3 -0
- package/templates/react-nest-antd/backend/prisma/migrations/migration_lock.toml +1 -0
- package/templates/react-nest-antd/backend/prisma/schema.prisma +25 -0
- package/templates/react-nest-antd/backend/scripts/seed.ts +4 -0
- package/templates/react-nest-antd/backend/src/app.module.ts +43 -0
- package/templates/react-nest-antd/backend/src/main.ts +6 -0
- package/templates/react-nest-antd/backend/src/password.ts +3 -0
- package/templates/react-nest-antd/backend/src/validation.ts +7 -0
- package/templates/react-nest-antd/backend/test/api.test.ts +25 -0
- package/templates/react-nest-antd/backend/tsconfig.build.json +15 -0
- package/templates/react-nest-antd/backend/tsconfig.json +17 -0
- package/templates/react-nest-antd/compose.yaml +18 -0
- package/templates/react-nest-antd/design/guide.md +61 -0
- package/templates/react-nest-antd/design/layout.css +6 -0
- package/templates/react-nest-antd/design/structure.json +107 -0
- package/templates/react-nest-antd/design/tokens.json +171 -0
- package/templates/react-nest-antd/design/widgets.css +30 -0
- package/templates/react-nest-antd/design/widgets.json +233 -0
- package/templates/react-nest-antd/docs/PROJECT.md +9 -0
- package/templates/react-nest-antd/docs/api.d.ts +516 -0
- package/templates/react-nest-antd/docs/openapi.json +439 -0
- package/templates/react-nest-antd/gitignore.template +19 -0
- package/templates/react-nest-antd/licenses/fastapi.txt +21 -0
- package/templates/react-nest-antd/licenses/nest.txt +22 -0
- package/templates/react-nest-antd/licenses/next.txt +21 -0
- package/templates/react-nest-antd/licenses/shadcn.txt +21 -0
- package/templates/react-nest-antd/licenses/sources.json +27 -0
- package/templates/react-nest-antd/licenses/spring.txt +202 -0
- package/templates/react-nest-antd/package-lock.json +440 -0
- package/templates/react-nest-antd/package.json +21 -0
- package/templates/react-nest-antd/playwright.config.ts +3 -0
- package/templates/react-nest-antd/project.json +8 -0
- package/templates/react-nest-antd/scripts/design-coverage.mjs +20 -0
- package/templates/react-nest-antd/scripts/design-next-cleanup.mjs +13 -0
- package/templates/react-nest-antd/scripts/design-verify.mjs +154 -0
- package/templates/react-nest-antd/scripts/design.mjs +108 -0
- package/templates/react-nest-antd/scripts/project.mjs +118 -0
- package/templates/react-nest-antd/tests/contract.spec.ts +47 -0
- package/templates/react-nest-antd/tests/design/harness.tsx +63 -0
- package/templates/react-nest-antd/tests/ui.spec.ts +61 -0
- package/templates/react-nest-antd/web/eslint.config.mjs +3 -0
- package/templates/react-nest-antd/web/index.html +1 -0
- package/templates/react-nest-antd/web/package.json +28 -0
- package/templates/react-nest-antd/web/pnpm-lock.yaml +2215 -0
- package/templates/react-nest-antd/web/src/App.tsx +29 -0
- package/templates/react-nest-antd/web/src/design-layout.css +7 -0
- package/templates/react-nest-antd/web/src/design-runtime.json +511 -0
- package/templates/react-nest-antd/web/src/design-tokens.css +168 -0
- package/templates/react-nest-antd/web/src/design-widgets.css +31 -0
- package/templates/react-nest-antd/web/src/main.tsx +6 -0
- package/templates/react-nest-antd/web/src/structure-view.tsx +16 -0
- package/templates/react-nest-antd/web/src/styles.css +3 -0
- package/templates/react-nest-antd/web/src/ui.tsx +30 -0
- package/templates/react-nest-antd/web/src/widget-icon.tsx +5 -0
- package/templates/react-nest-antd/web/src/widget-types.ts +13 -0
- package/templates/react-nest-antd/web/src/workspace-model.ts +85 -0
- package/templates/react-nest-antd/web/tsconfig.json +22 -0
- package/templates/react-nest-antd/web/vite.config.ts +3 -0
- package/templates/react-nest-shadcn/.agents/skills/design-contract/SKILL.md +23 -0
- package/templates/react-nest-shadcn/.agents/skills/project-work/SKILL.md +8 -0
- package/templates/react-nest-shadcn/.claude/skills/design-contract/SKILL.md +23 -0
- package/templates/react-nest-shadcn/.claude/skills/project-work/SKILL.md +8 -0
- package/templates/react-nest-shadcn/.dockerignore +18 -0
- package/templates/react-nest-shadcn/.env.example +13 -0
- package/templates/react-nest-shadcn/.grok/skills/design-contract/SKILL.md +23 -0
- package/templates/react-nest-shadcn/.grok/skills/project-work/SKILL.md +8 -0
- package/templates/react-nest-shadcn/.scaffold-checks.json +7 -0
- package/templates/react-nest-shadcn/AGENTS.md +11 -0
- package/templates/react-nest-shadcn/CLAUDE.md +1 -0
- package/templates/react-nest-shadcn/DESIGN.md +208 -0
- package/templates/react-nest-shadcn/LICENSE +21 -0
- package/templates/react-nest-shadcn/README.md +55 -0
- package/templates/react-nest-shadcn/THIRD_PARTY_NOTICES.md +14 -0
- package/templates/react-nest-shadcn/backend/Dockerfile +12 -0
- package/templates/react-nest-shadcn/backend/eslint.config.mjs +3 -0
- package/templates/react-nest-shadcn/backend/jest.config.cjs +1 -0
- package/templates/react-nest-shadcn/backend/package.json +40 -0
- package/templates/react-nest-shadcn/backend/pnpm-lock.yaml +5165 -0
- package/templates/react-nest-shadcn/backend/pnpm-workspace.yaml +6 -0
- package/templates/react-nest-shadcn/backend/prisma/migrations/202610190001_initial/migration.sql +3 -0
- package/templates/react-nest-shadcn/backend/prisma/migrations/migration_lock.toml +1 -0
- package/templates/react-nest-shadcn/backend/prisma/schema.prisma +25 -0
- package/templates/react-nest-shadcn/backend/scripts/seed.ts +4 -0
- package/templates/react-nest-shadcn/backend/src/app.module.ts +43 -0
- package/templates/react-nest-shadcn/backend/src/main.ts +6 -0
- package/templates/react-nest-shadcn/backend/src/password.ts +3 -0
- package/templates/react-nest-shadcn/backend/src/validation.ts +7 -0
- package/templates/react-nest-shadcn/backend/test/api.test.ts +25 -0
- package/templates/react-nest-shadcn/backend/tsconfig.build.json +15 -0
- package/templates/react-nest-shadcn/backend/tsconfig.json +17 -0
- package/templates/react-nest-shadcn/compose.yaml +18 -0
- package/templates/react-nest-shadcn/design/guide.md +61 -0
- package/templates/react-nest-shadcn/design/layout.css +6 -0
- package/templates/react-nest-shadcn/design/structure.json +107 -0
- package/templates/react-nest-shadcn/design/tokens.json +171 -0
- package/templates/react-nest-shadcn/design/widgets.css +30 -0
- package/templates/react-nest-shadcn/design/widgets.json +233 -0
- package/templates/react-nest-shadcn/docs/PROJECT.md +9 -0
- package/templates/react-nest-shadcn/docs/api.d.ts +516 -0
- package/templates/react-nest-shadcn/docs/openapi.json +439 -0
- package/templates/react-nest-shadcn/gitignore.template +19 -0
- package/templates/react-nest-shadcn/licenses/fastapi.txt +21 -0
- package/templates/react-nest-shadcn/licenses/nest.txt +22 -0
- package/templates/react-nest-shadcn/licenses/next.txt +21 -0
- package/templates/react-nest-shadcn/licenses/shadcn.txt +21 -0
- package/templates/react-nest-shadcn/licenses/sources.json +27 -0
- package/templates/react-nest-shadcn/licenses/spring.txt +202 -0
- package/templates/react-nest-shadcn/package-lock.json +440 -0
- package/templates/react-nest-shadcn/package.json +21 -0
- package/templates/react-nest-shadcn/playwright.config.ts +3 -0
- package/templates/react-nest-shadcn/project.json +8 -0
- package/templates/react-nest-shadcn/scripts/design-coverage.mjs +20 -0
- package/templates/react-nest-shadcn/scripts/design-next-cleanup.mjs +13 -0
- package/templates/react-nest-shadcn/scripts/design-verify.mjs +154 -0
- package/templates/react-nest-shadcn/scripts/design.mjs +108 -0
- package/templates/react-nest-shadcn/scripts/project.mjs +118 -0
- package/templates/react-nest-shadcn/tests/contract.spec.ts +47 -0
- package/templates/react-nest-shadcn/tests/design/harness.tsx +63 -0
- package/templates/react-nest-shadcn/tests/ui.spec.ts +61 -0
- package/templates/react-nest-shadcn/web/eslint.config.mjs +3 -0
- package/templates/react-nest-shadcn/web/index.html +1 -0
- package/templates/react-nest-shadcn/web/package.json +33 -0
- package/templates/react-nest-shadcn/web/pnpm-lock.yaml +1788 -0
- package/templates/react-nest-shadcn/web/src/App.tsx +30 -0
- package/templates/react-nest-shadcn/web/src/design-layout.css +7 -0
- package/templates/react-nest-shadcn/web/src/design-runtime.json +511 -0
- package/templates/react-nest-shadcn/web/src/design-tokens.css +168 -0
- package/templates/react-nest-shadcn/web/src/design-widgets.css +31 -0
- package/templates/react-nest-shadcn/web/src/main.tsx +6 -0
- package/templates/react-nest-shadcn/web/src/structure-view.tsx +16 -0
- package/templates/react-nest-shadcn/web/src/styles.css +3 -0
- package/templates/react-nest-shadcn/web/src/tailwind.css +2 -0
- package/templates/react-nest-shadcn/web/src/ui.tsx +13 -0
- package/templates/react-nest-shadcn/web/src/widget-icon.tsx +5 -0
- package/templates/react-nest-shadcn/web/src/widget-types.ts +13 -0
- package/templates/react-nest-shadcn/web/src/workspace-model.ts +85 -0
- package/templates/react-nest-shadcn/web/tsconfig.json +22 -0
- package/templates/react-nest-shadcn/web/vite.config.ts +4 -0
- package/templates/react-spring-antd/.agents/skills/design-contract/SKILL.md +23 -0
- package/templates/react-spring-antd/.agents/skills/project-work/SKILL.md +8 -0
- package/templates/react-spring-antd/.claude/skills/design-contract/SKILL.md +23 -0
- package/templates/react-spring-antd/.claude/skills/project-work/SKILL.md +8 -0
- package/templates/react-spring-antd/.dockerignore +18 -0
- package/templates/react-spring-antd/.env.example +13 -0
- package/templates/react-spring-antd/.grok/skills/design-contract/SKILL.md +23 -0
- package/templates/react-spring-antd/.grok/skills/project-work/SKILL.md +8 -0
- package/templates/react-spring-antd/.scaffold-checks.json +7 -0
- package/templates/react-spring-antd/AGENTS.md +11 -0
- package/templates/react-spring-antd/CLAUDE.md +1 -0
- package/templates/react-spring-antd/DESIGN.md +208 -0
- package/templates/react-spring-antd/LICENSE +21 -0
- package/templates/react-spring-antd/README.md +55 -0
- package/templates/react-spring-antd/THIRD_PARTY_NOTICES.md +14 -0
- package/templates/react-spring-antd/backend/.mvn/wrapper/maven-wrapper.properties +3 -0
- package/templates/react-spring-antd/backend/Dockerfile +11 -0
- package/templates/react-spring-antd/backend/mvnw +295 -0
- package/templates/react-spring-antd/backend/pom.xml +15 -0
- package/templates/react-spring-antd/backend/src/main/java/dev/scaffold/app/Api.java +38 -0
- package/templates/react-spring-antd/backend/src/main/java/dev/scaffold/app/AppUser.java +11 -0
- package/templates/react-spring-antd/backend/src/main/java/dev/scaffold/app/Application.java +7 -0
- package/templates/react-spring-antd/backend/src/main/java/dev/scaffold/app/Errors.java +13 -0
- package/templates/react-spring-antd/backend/src/main/java/dev/scaffold/app/PersonalRecord.java +15 -0
- package/templates/react-spring-antd/backend/src/main/java/dev/scaffold/app/Records.java +14 -0
- package/templates/react-spring-antd/backend/src/main/java/dev/scaffold/app/Security.java +28 -0
- package/templates/react-spring-antd/backend/src/main/java/dev/scaffold/app/Seed.java +13 -0
- package/templates/react-spring-antd/backend/src/main/java/dev/scaffold/app/Users.java +5 -0
- package/templates/react-spring-antd/backend/src/main/resources/application.properties +17 -0
- package/templates/react-spring-antd/backend/src/main/resources/db/migration/V1__initial.sql +3 -0
- package/templates/react-spring-antd/backend/src/main/resources/openapi.json +439 -0
- package/templates/react-spring-antd/backend/src/test/java/dev/scaffold/app/ApiTest.java +28 -0
- package/templates/react-spring-antd/backend/src/test/java/dev/scaffold/app/SessionExpiryTest.java +37 -0
- package/templates/react-spring-antd/compose.yaml +18 -0
- package/templates/react-spring-antd/design/guide.md +61 -0
- package/templates/react-spring-antd/design/layout.css +6 -0
- package/templates/react-spring-antd/design/structure.json +107 -0
- package/templates/react-spring-antd/design/tokens.json +171 -0
- package/templates/react-spring-antd/design/widgets.css +30 -0
- package/templates/react-spring-antd/design/widgets.json +233 -0
- package/templates/react-spring-antd/docs/PROJECT.md +9 -0
- package/templates/react-spring-antd/docs/api.d.ts +516 -0
- package/templates/react-spring-antd/docs/openapi.json +439 -0
- package/templates/react-spring-antd/gitignore.template +19 -0
- package/templates/react-spring-antd/licenses/fastapi.txt +21 -0
- package/templates/react-spring-antd/licenses/nest.txt +22 -0
- package/templates/react-spring-antd/licenses/next.txt +21 -0
- package/templates/react-spring-antd/licenses/shadcn.txt +21 -0
- package/templates/react-spring-antd/licenses/sources.json +27 -0
- package/templates/react-spring-antd/licenses/spring.txt +202 -0
- package/templates/react-spring-antd/package-lock.json +440 -0
- package/templates/react-spring-antd/package.json +21 -0
- package/templates/react-spring-antd/playwright.config.ts +3 -0
- package/templates/react-spring-antd/project.json +8 -0
- package/templates/react-spring-antd/scripts/design-coverage.mjs +20 -0
- package/templates/react-spring-antd/scripts/design-next-cleanup.mjs +13 -0
- package/templates/react-spring-antd/scripts/design-verify.mjs +154 -0
- package/templates/react-spring-antd/scripts/design.mjs +108 -0
- package/templates/react-spring-antd/scripts/project.mjs +118 -0
- package/templates/react-spring-antd/tests/contract.spec.ts +47 -0
- package/templates/react-spring-antd/tests/design/harness.tsx +63 -0
- package/templates/react-spring-antd/tests/ui.spec.ts +61 -0
- package/templates/react-spring-antd/web/eslint.config.mjs +3 -0
- package/templates/react-spring-antd/web/index.html +1 -0
- package/templates/react-spring-antd/web/package.json +28 -0
- package/templates/react-spring-antd/web/pnpm-lock.yaml +2215 -0
- package/templates/react-spring-antd/web/src/App.tsx +29 -0
- package/templates/react-spring-antd/web/src/design-layout.css +7 -0
- package/templates/react-spring-antd/web/src/design-runtime.json +511 -0
- package/templates/react-spring-antd/web/src/design-tokens.css +168 -0
- package/templates/react-spring-antd/web/src/design-widgets.css +31 -0
- package/templates/react-spring-antd/web/src/main.tsx +6 -0
- package/templates/react-spring-antd/web/src/structure-view.tsx +16 -0
- package/templates/react-spring-antd/web/src/styles.css +3 -0
- package/templates/react-spring-antd/web/src/ui.tsx +30 -0
- package/templates/react-spring-antd/web/src/widget-icon.tsx +5 -0
- package/templates/react-spring-antd/web/src/widget-types.ts +13 -0
- package/templates/react-spring-antd/web/src/workspace-model.ts +85 -0
- package/templates/react-spring-antd/web/tsconfig.json +22 -0
- package/templates/react-spring-antd/web/vite.config.ts +3 -0
- package/templates/react-spring-shadcn/.agents/skills/design-contract/SKILL.md +23 -0
- package/templates/react-spring-shadcn/.agents/skills/project-work/SKILL.md +8 -0
- package/templates/react-spring-shadcn/.claude/skills/design-contract/SKILL.md +23 -0
- package/templates/react-spring-shadcn/.claude/skills/project-work/SKILL.md +8 -0
- package/templates/react-spring-shadcn/.dockerignore +18 -0
- package/templates/react-spring-shadcn/.env.example +13 -0
- package/templates/react-spring-shadcn/.grok/skills/design-contract/SKILL.md +23 -0
- package/templates/react-spring-shadcn/.grok/skills/project-work/SKILL.md +8 -0
- package/templates/react-spring-shadcn/.scaffold-checks.json +7 -0
- package/templates/react-spring-shadcn/AGENTS.md +11 -0
- package/templates/react-spring-shadcn/CLAUDE.md +1 -0
- package/templates/react-spring-shadcn/DESIGN.md +208 -0
- package/templates/react-spring-shadcn/LICENSE +21 -0
- package/templates/react-spring-shadcn/README.md +55 -0
- package/templates/react-spring-shadcn/THIRD_PARTY_NOTICES.md +14 -0
- package/templates/react-spring-shadcn/backend/.mvn/wrapper/maven-wrapper.properties +3 -0
- package/templates/react-spring-shadcn/backend/Dockerfile +11 -0
- package/templates/react-spring-shadcn/backend/mvnw +295 -0
- package/templates/react-spring-shadcn/backend/pom.xml +15 -0
- package/templates/react-spring-shadcn/backend/src/main/java/dev/scaffold/app/Api.java +38 -0
- package/templates/react-spring-shadcn/backend/src/main/java/dev/scaffold/app/AppUser.java +11 -0
- package/templates/react-spring-shadcn/backend/src/main/java/dev/scaffold/app/Application.java +7 -0
- package/templates/react-spring-shadcn/backend/src/main/java/dev/scaffold/app/Errors.java +13 -0
- package/templates/react-spring-shadcn/backend/src/main/java/dev/scaffold/app/PersonalRecord.java +15 -0
- package/templates/react-spring-shadcn/backend/src/main/java/dev/scaffold/app/Records.java +14 -0
- package/templates/react-spring-shadcn/backend/src/main/java/dev/scaffold/app/Security.java +28 -0
- package/templates/react-spring-shadcn/backend/src/main/java/dev/scaffold/app/Seed.java +13 -0
- package/templates/react-spring-shadcn/backend/src/main/java/dev/scaffold/app/Users.java +5 -0
- package/templates/react-spring-shadcn/backend/src/main/resources/application.properties +17 -0
- package/templates/react-spring-shadcn/backend/src/main/resources/db/migration/V1__initial.sql +3 -0
- package/templates/react-spring-shadcn/backend/src/main/resources/openapi.json +439 -0
- package/templates/react-spring-shadcn/backend/src/test/java/dev/scaffold/app/ApiTest.java +28 -0
- package/templates/react-spring-shadcn/backend/src/test/java/dev/scaffold/app/SessionExpiryTest.java +37 -0
- package/templates/react-spring-shadcn/compose.yaml +18 -0
- package/templates/react-spring-shadcn/design/guide.md +61 -0
- package/templates/react-spring-shadcn/design/layout.css +6 -0
- package/templates/react-spring-shadcn/design/structure.json +107 -0
- package/templates/react-spring-shadcn/design/tokens.json +171 -0
- package/templates/react-spring-shadcn/design/widgets.css +30 -0
- package/templates/react-spring-shadcn/design/widgets.json +233 -0
- package/templates/react-spring-shadcn/docs/PROJECT.md +9 -0
- package/templates/react-spring-shadcn/docs/api.d.ts +516 -0
- package/templates/react-spring-shadcn/docs/openapi.json +439 -0
- package/templates/react-spring-shadcn/gitignore.template +19 -0
- package/templates/react-spring-shadcn/licenses/fastapi.txt +21 -0
- package/templates/react-spring-shadcn/licenses/nest.txt +22 -0
- package/templates/react-spring-shadcn/licenses/next.txt +21 -0
- package/templates/react-spring-shadcn/licenses/shadcn.txt +21 -0
- package/templates/react-spring-shadcn/licenses/sources.json +27 -0
- package/templates/react-spring-shadcn/licenses/spring.txt +202 -0
- package/templates/react-spring-shadcn/package-lock.json +440 -0
- package/templates/react-spring-shadcn/package.json +21 -0
- package/templates/react-spring-shadcn/playwright.config.ts +3 -0
- package/templates/react-spring-shadcn/project.json +8 -0
- package/templates/react-spring-shadcn/scripts/design-coverage.mjs +20 -0
- package/templates/react-spring-shadcn/scripts/design-next-cleanup.mjs +13 -0
- package/templates/react-spring-shadcn/scripts/design-verify.mjs +154 -0
- package/templates/react-spring-shadcn/scripts/design.mjs +108 -0
- package/templates/react-spring-shadcn/scripts/project.mjs +118 -0
- package/templates/react-spring-shadcn/tests/contract.spec.ts +47 -0
- package/templates/react-spring-shadcn/tests/design/harness.tsx +63 -0
- package/templates/react-spring-shadcn/tests/ui.spec.ts +61 -0
- package/templates/react-spring-shadcn/web/eslint.config.mjs +3 -0
- package/templates/react-spring-shadcn/web/index.html +1 -0
- package/templates/react-spring-shadcn/web/package.json +33 -0
- package/templates/react-spring-shadcn/web/pnpm-lock.yaml +1788 -0
- package/templates/react-spring-shadcn/web/src/App.tsx +30 -0
- package/templates/react-spring-shadcn/web/src/design-layout.css +7 -0
- package/templates/react-spring-shadcn/web/src/design-runtime.json +511 -0
- package/templates/react-spring-shadcn/web/src/design-tokens.css +168 -0
- package/templates/react-spring-shadcn/web/src/design-widgets.css +31 -0
- package/templates/react-spring-shadcn/web/src/main.tsx +6 -0
- package/templates/react-spring-shadcn/web/src/structure-view.tsx +16 -0
- package/templates/react-spring-shadcn/web/src/styles.css +3 -0
- package/templates/react-spring-shadcn/web/src/tailwind.css +2 -0
- package/templates/react-spring-shadcn/web/src/ui.tsx +13 -0
- package/templates/react-spring-shadcn/web/src/widget-icon.tsx +5 -0
- package/templates/react-spring-shadcn/web/src/widget-types.ts +13 -0
- package/templates/react-spring-shadcn/web/src/workspace-model.ts +85 -0
- package/templates/react-spring-shadcn/web/tsconfig.json +22 -0
- package/templates/react-spring-shadcn/web/vite.config.ts +4 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 qinchaomeishenmeshi
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
## 运行
|
|
2
|
+
|
|
3
|
+
需要 Node.js 24、Docker 和该模板的运行时(见 project.json 与下方说明)。
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm run setup
|
|
7
|
+
npm run dev
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
`setup` 安装依赖,然后显式启动本地 PostgreSQL、迁移并创建 A/B 开发账号。首次生成随机密码,登录信息在 Git 忽略的 `.scaffold-local-credentials`;不是生产默认密码。已有 `.env` 时保留配置,请仅使用本地开发实例。
|
|
11
|
+
|
|
12
|
+
默认数据库端口为 54329、API 为 8000、Web 为 5173(Next 为 3000)。首次 setup 可用 `POSTGRES_PORT`、`PORT`、`WEB_PORT` 环境变量指定空闲端口;后续沿用 `.env`。
|
|
13
|
+
|
|
14
|
+
页面名称与简介来自根 project.json;英文名用于目录和工程标识。基础示例只包含个人记录功能,不因简介自动新增业务。
|
|
15
|
+
|
|
16
|
+
## 验证
|
|
17
|
+
|
|
18
|
+
安装依赖后,由已安装的 CLI 执行:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
scaffold doctor --dir . --json
|
|
22
|
+
scaffold verify --dir . --profile baseline --json
|
|
23
|
+
scaffold report --dir . --json
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
verify 创建自己的临时 PostgreSQL 并注入连接,不使用开发 DATABASE_URL;完成后释放本次容器。单独运行项目命令时需要显式提供本地环境:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
node scripts/project.mjs typecheck
|
|
30
|
+
node scripts/project.mjs lint
|
|
31
|
+
node scripts/project.mjs build
|
|
32
|
+
node scripts/project.mjs test:native
|
|
33
|
+
node scripts/project.mjs test:api
|
|
34
|
+
node scripts/project.mjs test:e2e
|
|
35
|
+
node scripts/project.mjs api:generate
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
接口:docs/openapi.json;结构:docs/PROJECT.md;规则:AGENTS.md。按需运行 api:generate 更新 TypeScript 客户端类型,不在 verify 中修改源码。
|
|
39
|
+
|
|
40
|
+
## 认证边界
|
|
41
|
+
|
|
42
|
+
JWT 模板只在浏览器内存保存 Token,页面刷新需重新登录;退出清除内存,不声称服务器撤销旧 JWT。Session 模板使用 HttpOnly Cookie 和同源写入校验,退出后 Session 失效。所有记录访问由服务端按当前用户过滤。
|
|
43
|
+
|
|
44
|
+
## 容器构建
|
|
45
|
+
|
|
46
|
+
按模板提供的 Dockerfile 构建,配置自己的数据库和秘密;构建与本地验证不代表生产部署或业务验收通过。不要把 `.env`、凭据文件或运行报告加入镜像/版本库。
|
|
47
|
+
|
|
48
|
+
## 视觉设计
|
|
49
|
+
|
|
50
|
+
UI 开发前读根目录 DESIGN.md 和内置 design-contract Skill。`design/tokens.json`、`widgets.json`、`structure.json` 与公共 CSS 是组件库无关的设计源;`web/src/ui.tsx` 是所选组件库适配器;`workspace-model.ts` 管理业务。修改源后执行 `npm run design:sync`,再运行只读漂移检查 `npm run design:check` 和浏览器契约检查 `npm run design:verify`。后者临时创建测试入口,验证全部声明的组件状态及页面(桌面/移动端),输出 `reports/design-check/result.json`,结束后清理入口。需要已安装依赖及 Playwright Chromium。build/typecheck/lint 同样检查漂移。当前项目的 PASS 仅证明已选适配器;新增库须保持共享规范和业务不变,添加适配器、依赖及框架绑定,并在脚手架完整矩阵中复验。
|
|
51
|
+
|
|
52
|
+
## 本模板
|
|
53
|
+
|
|
54
|
+
技术栈:react-fastapi;UI:antd。需要 Python 3.12 + uv、Bun(前端)。
|
|
55
|
+
后端镜像:docker build backend;前端构建产物位于 web/dist,生产需要同源反向代理 /api 到后端。
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Template sources and licenses
|
|
2
|
+
|
|
3
|
+
Templates are maintained derivatives, not unmodified upstream distributions. Exact bundled files are hashed in templates/catalog.json; npm/uv/pnpm/Bun locks pin dependency resolution. Initialization is offline and never invokes upstream generators.
|
|
4
|
+
|
|
5
|
+
| Source | Fixed reference | Use / modifications | License |
|
|
6
|
+
| --- | --- | --- | --- |
|
|
7
|
+
| fastapi/full-stack-fastapi-template | b1125d8839482cb7bbae603ddc6d0081bf87532e | SQLModel/Alembic/JWT/pwdlib foundation; reduced accounts, replaced sample feature with owner-scoped records, retained Bun frontend | MIT, licenses/fastapi.txt |
|
|
8
|
+
| nestjs/typescript-starter | a122dea65cd0610ee205d7765ed46f9d73629141 | Nest module/bootstrap foundation; added Prisma, JWT/Guard, Jest/Supertest; no deployment tooling | MIT, licenses/nest.txt |
|
|
9
|
+
| Spring Initializr | starter.zip fetched 2026-10-19; Maven Wrapper and Java layout | Generator returned unresolved 4.1.1.RELEASE; parent adjusted to stable Maven Central 3.5.16, Session/JPA/Flyway/CRUD added | Apache-2.0 wrapper, licenses/spring.txt |
|
|
10
|
+
| create-next-app | npm 16.4.2 | Official App Router/TypeScript baseline; Better Auth + Prisma + records; no remote fonts | MIT, licenses/next.txt |
|
|
11
|
+
| shadcn/ui | Button/Input pattern, pinned source reference in licenses/sources.json | Adapted local CVA/Slot controls with Tailwind; retained copy ownership | MIT, licenses/shadcn.txt |
|
|
12
|
+
| Ant Design | npm 6.6.6 | Installed dependency; no copied source | MIT (package license) |
|
|
13
|
+
|
|
14
|
+
Package dependencies carry their own licenses. Generated apps include these notices; template authors must carry applicable notices when changing upstream-derived files. Names and marks remain their respective owners'.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.12
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
FROM python:3.12-slim
|
|
2
|
+
COPY --from=ghcr.io/astral-sh/uv:0.13.1 /uv /usr/local/bin/uv
|
|
3
|
+
WORKDIR /app
|
|
4
|
+
COPY pyproject.toml uv.lock ./
|
|
5
|
+
RUN uv sync --frozen --no-dev
|
|
6
|
+
COPY app ./app
|
|
7
|
+
COPY migrations ./migrations
|
|
8
|
+
COPY alembic.ini ./
|
|
9
|
+
EXPOSE 8000
|
|
10
|
+
CMD ["uv", "run", "--frozen", "--no-dev", "uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Adapted from the pinned FastAPI full-stack template; see THIRD_PARTY_NOTICES.md.
|
|
2
|
+
from datetime import UTC, datetime, timedelta
|
|
3
|
+
import os
|
|
4
|
+
import jwt
|
|
5
|
+
from pwdlib import PasswordHash
|
|
6
|
+
from pwdlib.hashers.argon2 import Argon2Hasher
|
|
7
|
+
from pwdlib.hashers.bcrypt import BcryptHasher
|
|
8
|
+
|
|
9
|
+
password_hash = PasswordHash((Argon2Hasher(), BcryptHasher()))
|
|
10
|
+
ALGORITHM = "HS256"
|
|
11
|
+
SECRET_KEY = os.environ["AUTH_SECRET"]
|
|
12
|
+
if len(SECRET_KEY) < 32:
|
|
13
|
+
raise RuntimeError("AUTH_SECRET must contain at least 32 characters")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def create_access_token(subject: str, expires_delta: timedelta = timedelta(minutes=15)) -> str:
|
|
17
|
+
return jwt.encode({"exp": datetime.now(UTC) + expires_delta, "sub": subject, "aud": "personal-records"}, SECRET_KEY, algorithm=ALGORITHM)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def verify_password(plain_password: str, hashed_password: str) -> bool:
|
|
21
|
+
return password_hash.verify(plain_password, hashed_password)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def get_password_hash(password: str) -> str:
|
|
25
|
+
return password_hash.hash(password)
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from collections.abc import Generator
|
|
3
|
+
from sqlmodel import Session, create_engine
|
|
4
|
+
|
|
5
|
+
url = os.environ["DATABASE_URL"].replace("postgresql://", "postgresql+psycopg://", 1)
|
|
6
|
+
engine = create_engine(url, pool_pre_ping=True, echo=False)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def get_session() -> Generator[Session, None, None]:
|
|
10
|
+
with Session(engine) as session:
|
|
11
|
+
yield session
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
from datetime import UTC, datetime
|
|
2
|
+
from typing import Annotated, Any
|
|
3
|
+
from uuid import UUID
|
|
4
|
+
import jwt
|
|
5
|
+
from fastapi import Depends, FastAPI, HTTPException, Query, Request, Response
|
|
6
|
+
from fastapi.exceptions import RequestValidationError
|
|
7
|
+
from fastapi.responses import JSONResponse
|
|
8
|
+
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
|
|
9
|
+
from pydantic import BaseModel, ConfigDict, field_validator
|
|
10
|
+
from sqlalchemy import func
|
|
11
|
+
from sqlmodel import Session, col, select
|
|
12
|
+
from app.core.security import ALGORITHM, SECRET_KEY, create_access_token, verify_password
|
|
13
|
+
from app.db import get_session
|
|
14
|
+
from app.models import PersonalRecord, User
|
|
15
|
+
|
|
16
|
+
app = FastAPI(title="Personal Records", docs_url="/api/docs", openapi_url="/api/openapi.json")
|
|
17
|
+
Db = Annotated[Session, Depends(get_session)]
|
|
18
|
+
bearer = HTTPBearer(auto_error=False)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@app.exception_handler(HTTPException)
|
|
22
|
+
async def http_error(_request: Request, exc: HTTPException) -> JSONResponse:
|
|
23
|
+
messages = {401: "请重新登录。", 404: "记录不存在。", 422: "输入不合法。"}
|
|
24
|
+
return JSONResponse(status_code=exc.status_code, content={"error": {"code": str(exc.status_code), "message": messages.get(exc.status_code, "请求失败。")}})
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@app.exception_handler(RequestValidationError)
|
|
28
|
+
async def validation_error(_request: Request, _exc: RequestValidationError) -> JSONResponse:
|
|
29
|
+
return JSONResponse(status_code=422, content={"error": {"code": "INVALID_INPUT", "message": "输入不合法,请检查字段和长度。"}})
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class Login(BaseModel):
|
|
33
|
+
model_config = ConfigDict(extra="forbid")
|
|
34
|
+
email: str
|
|
35
|
+
password: str
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class RecordInput(BaseModel):
|
|
39
|
+
model_config = ConfigDict(extra="forbid", strict=True)
|
|
40
|
+
title: str
|
|
41
|
+
content: str
|
|
42
|
+
|
|
43
|
+
@field_validator("title")
|
|
44
|
+
@classmethod
|
|
45
|
+
def valid_title(cls, value: str) -> str:
|
|
46
|
+
value = value.strip()
|
|
47
|
+
if not 1 <= len(value) <= 120:
|
|
48
|
+
raise ValueError("Invalid title length")
|
|
49
|
+
return value
|
|
50
|
+
|
|
51
|
+
@field_validator("content")
|
|
52
|
+
@classmethod
|
|
53
|
+
def valid_content(cls, value: str) -> str:
|
|
54
|
+
if len(value) > 10000:
|
|
55
|
+
raise ValueError("Invalid content length")
|
|
56
|
+
return value
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def current_user(db: Db, auth: Annotated[HTTPAuthorizationCredentials | None, Depends(bearer)]) -> User:
|
|
60
|
+
try:
|
|
61
|
+
if auth is None:
|
|
62
|
+
raise ValueError("missing")
|
|
63
|
+
claims = jwt.decode(auth.credentials, SECRET_KEY, algorithms=[ALGORITHM], audience="personal-records", options={"require": ["exp", "sub", "aud"]})
|
|
64
|
+
user = db.get(User, UUID(claims["sub"]))
|
|
65
|
+
if user is None:
|
|
66
|
+
raise ValueError("missing")
|
|
67
|
+
return user
|
|
68
|
+
except (jwt.InvalidTokenError, ValueError, KeyError):
|
|
69
|
+
raise HTTPException(401) from None
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
Identity = Annotated[User, Depends(current_user)]
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def public_record(row: PersonalRecord) -> dict[str, Any]:
|
|
76
|
+
return {"id": str(row.id), "title": row.title, "content": row.content, "created_at": row.created_at.isoformat(), "updated_at": row.updated_at.isoformat()}
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def owned(db: Session, record_id: UUID, user: User) -> PersonalRecord:
|
|
80
|
+
row = db.exec(select(PersonalRecord).where(PersonalRecord.id == record_id, PersonalRecord.owner_id == user.id)).first()
|
|
81
|
+
if row is None:
|
|
82
|
+
raise HTTPException(404)
|
|
83
|
+
return row
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
@app.get("/api/health")
|
|
87
|
+
def health() -> dict[str, str]:
|
|
88
|
+
return {"status": "ok"}
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
@app.post("/api/auth/login")
|
|
92
|
+
def login(body: Login, db: Db) -> dict[str, Any]:
|
|
93
|
+
user = db.exec(select(User).where(User.email == body.email.strip().lower())).first()
|
|
94
|
+
if user is None or not verify_password(body.password, user.hashed_password):
|
|
95
|
+
raise HTTPException(401)
|
|
96
|
+
return {"user": {"id": str(user.id), "email": user.email}, "token": create_access_token(str(user.id)), "mode": "jwt"}
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
@app.get("/api/auth/me")
|
|
100
|
+
def me(user: Identity) -> dict[str, Any]:
|
|
101
|
+
return {"user": {"id": str(user.id), "email": user.email}}
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
@app.post("/api/auth/logout", status_code=204)
|
|
105
|
+
def logout(_user: Identity) -> Response:
|
|
106
|
+
return Response(status_code=204)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
@app.get("/api/records")
|
|
110
|
+
def records(user: Identity, db: Db, page: Annotated[int, Query(ge=1, le=1000000)] = 1, pageSize: Annotated[int, Query(ge=1, le=100)] = 10) -> dict[str, Any]:
|
|
111
|
+
total = db.exec(select(func.count()).select_from(PersonalRecord).where(PersonalRecord.owner_id == user.id)).one()
|
|
112
|
+
rows = db.exec(select(PersonalRecord).where(PersonalRecord.owner_id == user.id).order_by(col(PersonalRecord.created_at).desc(), col(PersonalRecord.id).desc()).offset((page - 1) * pageSize).limit(pageSize)).all()
|
|
113
|
+
return {"items": [public_record(row) for row in rows], "total": total, "page": page, "pageSize": pageSize}
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
@app.post("/api/records", status_code=201)
|
|
117
|
+
def create(body: RecordInput, user: Identity, db: Db) -> dict[str, Any]:
|
|
118
|
+
row = PersonalRecord(owner_id=user.id, **body.model_dump())
|
|
119
|
+
db.add(row)
|
|
120
|
+
db.commit()
|
|
121
|
+
db.refresh(row)
|
|
122
|
+
return public_record(row)
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
@app.get("/api/records/{record_id}")
|
|
126
|
+
def detail(record_id: UUID, user: Identity, db: Db) -> dict[str, Any]:
|
|
127
|
+
return public_record(owned(db, record_id, user))
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
@app.put("/api/records/{record_id}")
|
|
131
|
+
def update(record_id: UUID, body: RecordInput, user: Identity, db: Db) -> dict[str, Any]:
|
|
132
|
+
row = owned(db, record_id, user)
|
|
133
|
+
row.title, row.content = body.title, body.content
|
|
134
|
+
row.updated_at = datetime.now(UTC)
|
|
135
|
+
db.add(row)
|
|
136
|
+
db.commit()
|
|
137
|
+
db.refresh(row)
|
|
138
|
+
return public_record(row)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
@app.delete("/api/records/{record_id}", status_code=204)
|
|
142
|
+
def delete(record_id: UUID, user: Identity, db: Db) -> Response:
|
|
143
|
+
row = owned(db, record_id, user)
|
|
144
|
+
db.delete(row)
|
|
145
|
+
db.commit()
|
|
146
|
+
return Response(status_code=204)
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from datetime import UTC, datetime
|
|
2
|
+
from uuid import UUID, uuid4
|
|
3
|
+
from sqlmodel import SQLModel, Field
|
|
4
|
+
from sqlalchemy import Column, DateTime, Text
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class User(SQLModel, table=True):
|
|
8
|
+
__tablename__ = "app_user"
|
|
9
|
+
id: UUID = Field(default_factory=uuid4, primary_key=True)
|
|
10
|
+
email: str = Field(unique=True, index=True)
|
|
11
|
+
hashed_password: str
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class PersonalRecord(SQLModel, table=True):
|
|
15
|
+
__tablename__ = "personal_record"
|
|
16
|
+
id: UUID = Field(default_factory=uuid4, primary_key=True)
|
|
17
|
+
owner_id: UUID = Field(foreign_key="app_user.id", index=True)
|
|
18
|
+
title: str
|
|
19
|
+
content: str = Field(sa_column=Column(Text, nullable=False))
|
|
20
|
+
created_at: datetime = Field(default_factory=lambda: datetime.now(UTC), sa_column=Column(DateTime(timezone=True), nullable=False))
|
|
21
|
+
updated_at: datetime = Field(default_factory=lambda: datetime.now(UTC), sa_column=Column(DateTime(timezone=True), nullable=False))
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from sqlmodel import Session, select
|
|
3
|
+
from app.core.security import get_password_hash
|
|
4
|
+
from app.db import engine
|
|
5
|
+
from app.models import User
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def main() -> None:
|
|
9
|
+
password = os.environ["SEED_PASSWORD"]
|
|
10
|
+
if len(password) < 12:
|
|
11
|
+
raise RuntimeError("Development/test seed password must be at least 12 characters")
|
|
12
|
+
with Session(engine) as db:
|
|
13
|
+
for key in ("SEED_A_EMAIL", "SEED_B_EMAIL"):
|
|
14
|
+
email = os.environ[key].strip().lower()
|
|
15
|
+
if not db.exec(select(User).where(User.email == email)).first():
|
|
16
|
+
db.add(User(email=email, hashed_password=get_password_hash(password)))
|
|
17
|
+
db.commit()
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
if __name__ == "__main__":
|
|
21
|
+
main()
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
from alembic import context
|
|
2
|
+
from sqlmodel import SQLModel
|
|
3
|
+
from app.db import engine
|
|
4
|
+
from app import models # noqa: F401
|
|
5
|
+
|
|
6
|
+
with engine.connect() as connection:
|
|
7
|
+
context.configure(connection=connection, target_metadata=SQLModel.metadata)
|
|
8
|
+
with context.begin_transaction():
|
|
9
|
+
context.run_migrations()
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from alembic import op
|
|
2
|
+
import sqlalchemy as sa
|
|
3
|
+
revision = "0001"
|
|
4
|
+
down_revision = None
|
|
5
|
+
branch_labels = None
|
|
6
|
+
depends_on = None
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def upgrade():
|
|
10
|
+
op.create_table("app_user", sa.Column("id", sa.Uuid(), primary_key=True), sa.Column("email", sa.String(), nullable=False), sa.Column("hashed_password", sa.String(), nullable=False))
|
|
11
|
+
op.create_index("ix_app_user_email", "app_user", ["email"], unique=True)
|
|
12
|
+
op.create_table("personal_record", sa.Column("id", sa.Uuid(), primary_key=True), sa.Column("owner_id", sa.Uuid(), sa.ForeignKey("app_user.id"), nullable=False), sa.Column("title", sa.String(), nullable=False), sa.Column("content", sa.Text(), nullable=False), sa.Column("created_at", sa.DateTime(timezone=True), nullable=False), sa.Column("updated_at", sa.DateTime(timezone=True), nullable=False))
|
|
13
|
+
op.create_index("ix_personal_record_owner_id", "personal_record", ["owner_id"])
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def downgrade():
|
|
17
|
+
op.drop_table("personal_record")
|
|
18
|
+
op.drop_table("app_user")
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "backend"
|
|
3
|
+
version = "1.0.0"
|
|
4
|
+
requires-python = ">=3.12,<3.13"
|
|
5
|
+
dependencies = ["fastapi[standard]==0.141.1", "sqlmodel==0.0.46", "alembic==1.19.1", "psycopg[binary]==3.3.6", "pyjwt==2.15.0", "pwdlib[argon2,bcrypt]==0.3.1", "pydantic==2.13.5", "httpx==0.28.1"]
|
|
6
|
+
[dependency-groups]
|
|
7
|
+
dev = ["pytest>=8,<10", "mypy>=1.18,<2", "ruff>=0.16,<1"]
|
|
8
|
+
[tool.mypy]
|
|
9
|
+
python_version = "3.12"
|
|
10
|
+
strict = true
|
|
11
|
+
[tool.ruff]
|
|
12
|
+
target-version = "py312"
|
|
13
|
+
[tool.ruff.lint]
|
|
14
|
+
select = ["E4", "E7", "E9", "F"]
|
|
15
|
+
[tool.pytest.ini_options]
|
|
16
|
+
testpaths = ["tests"]
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from datetime import timedelta
|
|
3
|
+
from fastapi.testclient import TestClient
|
|
4
|
+
from app.main import app
|
|
5
|
+
from app.core.security import create_access_token
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def test_identity_persistence_and_ownership():
|
|
9
|
+
with TestClient(app) as c:
|
|
10
|
+
assert c.get("/api/records").status_code == 401
|
|
11
|
+
login = c.post("/api/auth/login", json={"email": os.environ["SEED_A_EMAIL"], "password": os.environ["SEED_PASSWORD"]}).json()
|
|
12
|
+
a = {"Authorization": "Bearer " + login["token"]}
|
|
13
|
+
expired = create_access_token(login["user"]["id"], timedelta(seconds=-10))
|
|
14
|
+
assert c.get("/api/records", headers={"Authorization": "Bearer " + expired}).status_code == 401
|
|
15
|
+
btoken = c.post("/api/auth/login", json={"email": os.environ["SEED_B_EMAIL"], "password": os.environ["SEED_PASSWORD"]}).json()["token"]
|
|
16
|
+
b = {"Authorization": "Bearer " + btoken}
|
|
17
|
+
assert c.post("/api/records", headers=a, json={"title": "x", "content": "", "owner_id": login["user"]["id"]}).status_code == 422
|
|
18
|
+
row = c.post("/api/records", headers=a, json={"title": " native test ", "content": "persisted"}).json()
|
|
19
|
+
path = "/api/records/" + row["id"]
|
|
20
|
+
assert c.get(path, headers=a).json()["content"] == "persisted"
|
|
21
|
+
assert c.get(path, headers=b).status_code == 404
|
|
22
|
+
assert c.put(path, headers=b, json={"title": "x", "content": ""}).status_code == 404
|
|
23
|
+
assert c.delete(path, headers=b).status_code == 404
|
|
24
|
+
assert c.put(path, headers=a, json={"title": "", "content": ""}).status_code == 422
|
|
25
|
+
assert c.get(path, headers=a).json()["title"] == "native test"
|
|
26
|
+
assert c.delete(path, headers=a).status_code == 204
|
|
27
|
+
assert c.get(path, headers=a).status_code == 404
|