cfsa-antigravity 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/bin/cli.mjs +324 -0
- package/package.json +34 -0
- package/template/.agent/instructions/commands.md +48 -0
- package/template/.agent/instructions/patterns.md +61 -0
- package/template/.agent/instructions/structure.md +29 -0
- package/template/.agent/instructions/tech-stack.md +43 -0
- package/template/.agent/instructions/workflow.md +41 -0
- package/template/.agent/kit-sync.md +15 -0
- package/template/.agent/rules/boundary-not-placeholder.md +146 -0
- package/template/.agent/rules/completion-checklist.md +48 -0
- package/template/.agent/rules/decision-classification.md +103 -0
- package/template/.agent/rules/extensibility.md +47 -0
- package/template/.agent/rules/question-vs-command.md +81 -0
- package/template/.agent/rules/security-first.md +43 -0
- package/template/.agent/rules/specificity-standards.md +54 -0
- package/template/.agent/rules/tdd-contract-first.md +57 -0
- package/template/.agent/rules/vertical-slices.md +42 -0
- package/template/.agent/skill-library/MANIFEST.md +480 -0
- package/template/.agent/skill-library/README.md +38 -0
- package/template/.agent/skill-library/meta/brand-guidelines/SKILL.md +73 -0
- package/template/.agent/skill-library/meta/claude-code/README.md +9 -0
- package/template/.agent/skill-library/meta/claude-code/agent-development/SKILL.md +415 -0
- package/template/.agent/skill-library/meta/claude-code/hook-development/SKILL.md +712 -0
- package/template/.agent/skill-library/meta/claude-code/plugin-structure/SKILL.md +476 -0
- package/template/.agent/skill-library/meta/git-advanced/SKILL.md +972 -0
- package/template/.agent/skill-library/meta/mcp-builder/SKILL.md +236 -0
- package/template/.agent/skill-library/meta/product-marketing-context/SKILL.md +241 -0
- package/template/.agent/skill-library/meta/regex-patterns/SKILL.md +751 -0
- package/template/.agent/skill-library/meta/tmux-processes/SKILL.md +210 -0
- package/template/.agent/skill-library/meta/using-tmux-for-interactive-commands/SKILL.md +178 -0
- package/template/.agent/skill-library/stack/3d/threejs-pro/SKILL.md +300 -0
- package/template/.agent/skill-library/stack/ai/ai-sdk/SKILL.md +77 -0
- package/template/.agent/skill-library/stack/ai/langchain/SKILL.md +530 -0
- package/template/.agent/skill-library/stack/ai/ollama/SKILL.md +321 -0
- package/template/.agent/skill-library/stack/ai/openai-sdk/SKILL.md +549 -0
- package/template/.agent/skill-library/stack/analytics/google-analytics/SKILL.md +153 -0
- package/template/.agent/skill-library/stack/api/graphql/SKILL.md +1061 -0
- package/template/.agent/skill-library/stack/api/trpc/SKILL.md +576 -0
- package/template/.agent/skill-library/stack/auth/authjs/SKILL.md +569 -0
- package/template/.agent/skill-library/stack/auth/clerk/SKILL.md +590 -0
- package/template/.agent/skill-library/stack/auth/firebase-auth/SKILL.md +734 -0
- package/template/.agent/skill-library/stack/cms/payload-cms/SKILL.md +573 -0
- package/template/.agent/skill-library/stack/cms/shopify/SKILL.md +1193 -0
- package/template/.agent/skill-library/stack/cms/wordpress/SKILL.md +1104 -0
- package/template/.agent/skill-library/stack/css/sass-scss/SKILL.md +1121 -0
- package/template/.agent/skill-library/stack/css/tailwind-css-patterns/SKILL.md +863 -0
- package/template/.agent/skill-library/stack/css/tailwind-design-system/SKILL.md +490 -0
- package/template/.agent/skill-library/stack/css/vanilla-css/SKILL.md +1078 -0
- package/template/.agent/skill-library/stack/databases/clickhouse/SKILL.md +311 -0
- package/template/.agent/skill-library/stack/databases/influxdb/SKILL.md +280 -0
- package/template/.agent/skill-library/stack/databases/lancedb/SKILL.md +415 -0
- package/template/.agent/skill-library/stack/databases/mongodb/SKILL.md +1169 -0
- package/template/.agent/skill-library/stack/databases/neo4j/SKILL.md +839 -0
- package/template/.agent/skill-library/stack/databases/pgvector/SKILL.md +241 -0
- package/template/.agent/skill-library/stack/databases/pinecone/SKILL.md +212 -0
- package/template/.agent/skill-library/stack/databases/postgresql/SKILL.md +658 -0
- package/template/.agent/skill-library/stack/databases/qdrant/SKILL.md +312 -0
- package/template/.agent/skill-library/stack/databases/redis/SKILL.md +1079 -0
- package/template/.agent/skill-library/stack/databases/spacetimedb/SKILL.md +532 -0
- package/template/.agent/skill-library/stack/databases/sqlite/SKILL.md +1132 -0
- package/template/.agent/skill-library/stack/databases/supabase/SKILL.md +640 -0
- package/template/.agent/skill-library/stack/databases/surrealdb-expert/SKILL.md +945 -0
- package/template/.agent/skill-library/stack/databases/timescaledb/SKILL.md +745 -0
- package/template/.agent/skill-library/stack/databases/weaviate/SKILL.md +218 -0
- package/template/.agent/skill-library/stack/devops/github-actions/SKILL.md +554 -0
- package/template/.agent/skill-library/stack/devops/kubernetes/SKILL.md +950 -0
- package/template/.agent/skill-library/stack/devops/nginx/SKILL.md +841 -0
- package/template/.agent/skill-library/stack/devops/terraform/SKILL.md +860 -0
- package/template/.agent/skill-library/stack/email/resend/SKILL.md +391 -0
- package/template/.agent/skill-library/stack/engines/godot/SKILL.md +488 -0
- package/template/.agent/skill-library/stack/extensions/chrome-extension/SKILL.md +375 -0
- package/template/.agent/skill-library/stack/extensions/vscode-extension/SKILL.md +453 -0
- package/template/.agent/skill-library/stack/frameworks/astro-framework/SKILL.md +162 -0
- package/template/.agent/skill-library/stack/frameworks/electron/SKILL.md +1286 -0
- package/template/.agent/skill-library/stack/frameworks/fastapi/SKILL.md +650 -0
- package/template/.agent/skill-library/stack/frameworks/hono/SKILL.md +90 -0
- package/template/.agent/skill-library/stack/frameworks/nestjs/SKILL.md +878 -0
- package/template/.agent/skill-library/stack/frameworks/nextjs/SKILL.md +635 -0
- package/template/.agent/skill-library/stack/frameworks/nuxt/SKILL.md +564 -0
- package/template/.agent/skill-library/stack/frameworks/sveltekit/SKILL.md +614 -0
- package/template/.agent/skill-library/stack/frameworks/tauri/SKILL.md +920 -0
- package/template/.agent/skill-library/stack/gamedev/godot/SKILL.md +1032 -0
- package/template/.agent/skill-library/stack/gamedev/unity/SKILL.md +1175 -0
- package/template/.agent/skill-library/stack/hosting/aws/SKILL.md +467 -0
- package/template/.agent/skill-library/stack/hosting/cloudflare/SKILL.md +201 -0
- package/template/.agent/skill-library/stack/hosting/docker-expert/SKILL.md +409 -0
- package/template/.agent/skill-library/stack/hosting/vercel/SKILL.md +484 -0
- package/template/.agent/skill-library/stack/languages/bash-scripting/SKILL.md +773 -0
- package/template/.agent/skill-library/stack/languages/c-cpp/SKILL.md +712 -0
- package/template/.agent/skill-library/stack/languages/gdscript/SKILL.md +789 -0
- package/template/.agent/skill-library/stack/languages/go/SKILL.md +664 -0
- package/template/.agent/skill-library/stack/languages/java/SKILL.md +778 -0
- package/template/.agent/skill-library/stack/languages/kotlin/SKILL.md +665 -0
- package/template/.agent/skill-library/stack/languages/python/SKILL.md +678 -0
- package/template/.agent/skill-library/stack/languages/rust/SKILL.md +673 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/SKILL.md +141 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/advanced-generics.md +90 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/branded-types.md +57 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/builder-pattern.md +71 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/common-pitfalls.md +135 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/conditional-types.md +27 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/decorators.md +98 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/discriminated-unions.md +62 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/mapped-types.md +53 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/performance-best-practices.md +104 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/template-literal-types.md +49 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/testing-types.md +112 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/type-guards.md +70 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/type-inference.md +101 -0
- package/template/.agent/skill-library/stack/languages/typescript-advanced-patterns/references/utility-types.md +98 -0
- package/template/.agent/skill-library/stack/languages/vanilla-javascript/SKILL.md +803 -0
- package/template/.agent/skill-library/stack/messaging/kafka/SKILL.md +235 -0
- package/template/.agent/skill-library/stack/mobile/expo-react-native/SKILL.md +665 -0
- package/template/.agent/skill-library/stack/mobile/flutter/SKILL.md +316 -0
- package/template/.agent/skill-library/stack/mobile/react-native/SKILL.md +337 -0
- package/template/.agent/skill-library/stack/monitoring/posthog/SKILL.md +396 -0
- package/template/.agent/skill-library/stack/monitoring/sentry/SKILL.md +509 -0
- package/template/.agent/skill-library/stack/observability/datadog/SKILL.md +179 -0
- package/template/.agent/skill-library/stack/observability/distributed-tracing/SKILL.md +140 -0
- package/template/.agent/skill-library/stack/observability/logging-best-practices/SKILL.md +168 -0
- package/template/.agent/skill-library/stack/observability/opentelemetry/SKILL.md +164 -0
- package/template/.agent/skill-library/stack/observability/prometheus-grafana/SKILL.md +246 -0
- package/template/.agent/skill-library/stack/observability/python-observability/SKILL.md +158 -0
- package/template/.agent/skill-library/stack/orm/drizzle-orm/SKILL.md +613 -0
- package/template/.agent/skill-library/stack/orm/prisma/SKILL.md +744 -0
- package/template/.agent/skill-library/stack/payments/lemonsqueezy/SKILL.md +393 -0
- package/template/.agent/skill-library/stack/payments/stripe-integration/SKILL.md +457 -0
- package/template/.agent/skill-library/stack/queue/bullmq/SKILL.md +385 -0
- package/template/.agent/skill-library/stack/queue/inngest/SKILL.md +438 -0
- package/template/.agent/skill-library/stack/realtime/socketio/SKILL.md +595 -0
- package/template/.agent/skill-library/stack/search/elasticsearch/SKILL.md +248 -0
- package/template/.agent/skill-library/stack/search/meilisearch/SKILL.md +385 -0
- package/template/.agent/skill-library/stack/security/crypto-patterns/SKILL.md +437 -0
- package/template/.agent/skill-library/stack/security/csp-cors-headers/SKILL.md +588 -0
- package/template/.agent/skill-library/stack/security/dependency-auditing/SKILL.md +560 -0
- package/template/.agent/skill-library/stack/security/input-sanitization/SKILL.md +430 -0
- package/template/.agent/skill-library/stack/security/owasp-web-security/SKILL.md +421 -0
- package/template/.agent/skill-library/stack/state/tanstack-query/SKILL.md +637 -0
- package/template/.agent/skill-library/stack/state/zustand/SKILL.md +483 -0
- package/template/.agent/skill-library/stack/storage/aws-s3/SKILL.md +415 -0
- package/template/.agent/skill-library/stack/testing/playwright/SKILL.md +641 -0
- package/template/.agent/skill-library/stack/testing/storybook/SKILL.md +923 -0
- package/template/.agent/skill-library/stack/testing/testing-library/SKILL.md +872 -0
- package/template/.agent/skill-library/stack/testing/vitest/SKILL.md +714 -0
- package/template/.agent/skill-library/stack/ui/react-best-practices/SKILL.md +877 -0
- package/template/.agent/skill-library/stack/ui/react-composition-patterns/SKILL.md +1107 -0
- package/template/.agent/skill-library/stack/ui/react-flow/SKILL.md +425 -0
- package/template/.agent/skill-library/stack/ui/shadcn-ui/SKILL.md +703 -0
- package/template/.agent/skill-library/surface/api/api-caching/SKILL.md +458 -0
- package/template/.agent/skill-library/surface/api/api-documentation-openapi/SKILL.md +697 -0
- package/template/.agent/skill-library/surface/api/api-error-handling/SKILL.md +478 -0
- package/template/.agent/skill-library/surface/api/api-security-checklist/SKILL.md +147 -0
- package/template/.agent/skill-library/surface/api/api-versioning/SKILL.md +420 -0
- package/template/.agent/skill-library/surface/api/email-best-practices/SKILL.md +59 -0
- package/template/.agent/skill-library/surface/api/rate-limiting-abuse-protection/SKILL.md +147 -0
- package/template/.agent/skill-library/surface/api/rest-api-design/SKILL.md +478 -0
- package/template/.agent/skill-library/surface/api/webhook-design/SKILL.md +752 -0
- package/template/.agent/skill-library/surface/cli/cli-configuration-management/SKILL.md +445 -0
- package/template/.agent/skill-library/surface/cli/cli-error-diagnostics/SKILL.md +515 -0
- package/template/.agent/skill-library/surface/cli/cli-shell-integration/SKILL.md +479 -0
- package/template/.agent/skill-library/surface/cli/cli-ux-design/SKILL.md +477 -0
- package/template/.agent/skill-library/surface/desktop/desktop-app-distribution/SKILL.md +416 -0
- package/template/.agent/skill-library/surface/desktop/desktop-security-sandboxing/SKILL.md +407 -0
- package/template/.agent/skill-library/surface/desktop/desktop-ux-conventions/SKILL.md +361 -0
- package/template/.agent/skill-library/surface/desktop/native-os-integration/SKILL.md +563 -0
- package/template/.agent/skill-library/surface/extension/browser-extension-patterns/SKILL.md +482 -0
- package/template/.agent/skill-library/surface/extension/plugin-architecture-design/SKILL.md +632 -0
- package/template/.agent/skill-library/surface/extension/vscode-extension-development/SKILL.md +728 -0
- package/template/.agent/skill-library/surface/mobile/app-store-submission/SKILL.md +304 -0
- package/template/.agent/skill-library/surface/mobile/mobile-offline-sync/SKILL.md +443 -0
- package/template/.agent/skill-library/surface/mobile/mobile-responsive-patterns/SKILL.md +432 -0
- package/template/.agent/skill-library/surface/mobile/push-notifications/SKILL.md +495 -0
- package/template/.agent/skill-library/surface/web/accessibility-compliance/SKILL.md +827 -0
- package/template/.agent/skill-library/surface/web/ai-seo/SKILL.md +398 -0
- package/template/.agent/skill-library/surface/web/ai-seo/references/content-patterns.md +285 -0
- package/template/.agent/skill-library/surface/web/ai-seo/references/platform-ranking-factors.md +152 -0
- package/template/.agent/skill-library/surface/web/analytics-tracking/SKILL.md +309 -0
- package/template/.agent/skill-library/surface/web/analytics-tracking/references/event-library.md +260 -0
- package/template/.agent/skill-library/surface/web/analytics-tracking/references/ga4-implementation.md +300 -0
- package/template/.agent/skill-library/surface/web/analytics-tracking/references/gtm-implementation.md +390 -0
- package/template/.agent/skill-library/surface/web/authentication-ui-flows/SKILL.md +530 -0
- package/template/.agent/skill-library/surface/web/dark-mode-theming/SKILL.md +516 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/SKILL.md +105 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/charts.csv +26 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/colors.csv +97 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/landing.csv +31 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/styles.csv +59 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/typography.csv +58 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/data/ux-guidelines.csv +100 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/scripts/core.py +258 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/scripts/design_system.py +1067 -0
- package/template/.agent/skill-library/surface/web/design-reference-data/scripts/search.py +106 -0
- package/template/.agent/skill-library/surface/web/form-handling-validation/SKILL.md +675 -0
- package/template/.agent/skill-library/surface/web/frontend-design/SKILL.md +1393 -0
- package/template/.agent/skill-library/surface/web/frontend-design/templates/cppn-hero.tsx +299 -0
- package/template/.agent/skill-library/surface/web/frontend-design/templates/wave-hero.tsx +875 -0
- package/template/.agent/skill-library/surface/web/frontend-verification/SKILL.md +111 -0
- package/template/.agent/skill-library/surface/web/frontend-verification/scripts/ux_audit.py +739 -0
- package/template/.agent/skill-library/surface/web/i18n-localization/SKILL.md +154 -0
- package/template/.agent/skill-library/surface/web/offline-first-pwa/SKILL.md +657 -0
- package/template/.agent/skill-library/surface/web/page-cro/SKILL.md +182 -0
- package/template/.agent/skill-library/surface/web/page-cro/references/experiments.md +248 -0
- package/template/.agent/skill-library/surface/web/programmatic-seo/SKILL.md +238 -0
- package/template/.agent/skill-library/surface/web/programmatic-seo/references/playbooks.md +308 -0
- package/template/.agent/skill-library/surface/web/schema-markup/SKILL.md +179 -0
- package/template/.agent/skill-library/surface/web/schema-markup/references/schema-examples.md +398 -0
- package/template/.agent/skill-library/surface/web/seo-audit/SKILL.md +394 -0
- package/template/.agent/skill-library/surface/web/seo-audit/references/ai-writing-detection.md +200 -0
- package/template/.agent/skill-library/surface/web/web-performance-optimization/SKILL.md +646 -0
- package/template/.agent/skill-library/surface/web/web-scraping/SKILL.md +58 -0
- package/template/.agent/skills/accessibility/SKILL.md +522 -0
- package/template/.agent/skills/accessibility/references/WCAG.md +162 -0
- package/template/.agent/skills/adversarial-review/SKILL.md +90 -0
- package/template/.agent/skills/antigravity-workflows/SKILL.md +81 -0
- package/template/.agent/skills/antigravity-workflows/resources/implementation-playbook.md +36 -0
- package/template/.agent/skills/api-design-principles/SKILL.md +37 -0
- package/template/.agent/skills/api-design-principles/assets/api-design-checklist.md +155 -0
- package/template/.agent/skills/api-design-principles/assets/rest-api-template.py +182 -0
- package/template/.agent/skills/api-design-principles/references/graphql-schema-design.md +583 -0
- package/template/.agent/skills/api-design-principles/references/rest-best-practices.md +408 -0
- package/template/.agent/skills/api-design-principles/resources/implementation-playbook.md +513 -0
- package/template/.agent/skills/api-versioning/SKILL.md +420 -0
- package/template/.agent/skills/architecture-mapping/SKILL.md +219 -0
- package/template/.agent/skills/bootstrap-agents/SKILL.md +259 -0
- package/template/.agent/skills/brainstorming/SKILL.md +236 -0
- package/template/.agent/skills/brand-guidelines/SKILL.md +44 -0
- package/template/.agent/skills/clean-code/SKILL.md +94 -0
- package/template/.agent/skills/code-review-pro/SKILL.md +152 -0
- package/template/.agent/skills/concise-planning/SKILL.md +68 -0
- package/template/.agent/skills/cross-layer-consistency/SKILL.md +117 -0
- package/template/.agent/skills/database-schema-design/SKILL.md +429 -0
- package/template/.agent/skills/deployment-procedures/SKILL.md +241 -0
- package/template/.agent/skills/design-anti-cliche/SKILL.md +159 -0
- package/template/.agent/skills/design-direction/SKILL.md +45 -0
- package/template/.agent/skills/error-handling-patterns/SKILL.md +721 -0
- package/template/.agent/skills/find-skills/SKILL.md +145 -0
- package/template/.agent/skills/git-advanced/SKILL.md +972 -0
- package/template/.agent/skills/git-workflow/SKILL.md +420 -0
- package/template/.agent/skills/idea-extraction/SKILL.md +271 -0
- package/template/.agent/skills/logging-best-practices/SKILL.md +851 -0
- package/template/.agent/skills/migration-management/SKILL.md +384 -0
- package/template/.agent/skills/minimalist-surgical-development/SKILL.md +69 -0
- package/template/.agent/skills/parallel-agents/SKILL.md +165 -0
- package/template/.agent/skills/parallel-debugging/SKILL.md +135 -0
- package/template/.agent/skills/parallel-feature-development/SKILL.md +166 -0
- package/template/.agent/skills/performance-budgeting/SKILL.md +144 -0
- package/template/.agent/skills/pipeline-rubrics/SKILL.md +51 -0
- package/template/.agent/skills/pipeline-rubrics/references/architecture-rubric.md +19 -0
- package/template/.agent/skills/pipeline-rubrics/references/be-rubric.md +21 -0
- package/template/.agent/skills/pipeline-rubrics/references/fe-rubric.md +20 -0
- package/template/.agent/skills/pipeline-rubrics/references/ia-rubric.md +19 -0
- package/template/.agent/skills/pipeline-rubrics/references/scoring.md +28 -0
- package/template/.agent/skills/pipeline-rubrics/references/vision-rubric.md +11 -0
- package/template/.agent/skills/prd-templates/SKILL.md +88 -0
- package/template/.agent/skills/prd-templates/references/architecture-design-template.md +88 -0
- package/template/.agent/skills/prd-templates/references/be-spec-template.md +101 -0
- package/template/.agent/skills/prd-templates/references/data-placement-template.md +74 -0
- package/template/.agent/skills/prd-templates/references/decomposition-templates.md +211 -0
- package/template/.agent/skills/prd-templates/references/design-system-decisions.md +198 -0
- package/template/.agent/skills/prd-templates/references/engineering-standards-template.md +124 -0
- package/template/.agent/skills/prd-templates/references/fe-classification-procedures.md +47 -0
- package/template/.agent/skills/prd-templates/references/fe-spec-template.md +84 -0
- package/template/.agent/skills/prd-templates/references/infrastructure-report-template.md +71 -0
- package/template/.agent/skills/prd-templates/references/operational-templates.md +116 -0
- package/template/.agent/skills/prd-templates/references/placeholder-guard-template.md +21 -0
- package/template/.agent/skills/prd-templates/references/surface-model.md +61 -0
- package/template/.agent/skills/prd-templates/references/vision-template.md +66 -0
- package/template/.agent/skills/prompt-engineer/README.md +659 -0
- package/template/.agent/skills/prompt-engineer/SKILL.md +249 -0
- package/template/.agent/skills/regex-patterns/SKILL.md +751 -0
- package/template/.agent/skills/resolve-ambiguity/SKILL.md +278 -0
- package/template/.agent/skills/rest-api-design/SKILL.md +478 -0
- package/template/.agent/skills/security-scanning-security-hardening/SKILL.md +231 -0
- package/template/.agent/skills/session-continuity/SKILL.md +730 -0
- package/template/.agent/skills/session-continuity/protocols/01-session-resumption.md +38 -0
- package/template/.agent/skills/session-continuity/protocols/02-progress-generation.md +85 -0
- package/template/.agent/skills/session-continuity/protocols/03-progress-update.md +70 -0
- package/template/.agent/skills/session-continuity/protocols/04-pattern-extraction.md +60 -0
- package/template/.agent/skills/session-continuity/protocols/05-session-close.md +37 -0
- package/template/.agent/skills/session-continuity/protocols/06-decision-analysis.md +84 -0
- package/template/.agent/skills/session-continuity/protocols/07-spec-pipeline-generation.md +48 -0
- package/template/.agent/skills/session-continuity/protocols/08-spec-pipeline-update.md +43 -0
- package/template/.agent/skills/session-continuity/protocols/09-parallel-claim.md +122 -0
- package/template/.agent/skills/session-continuity/protocols/10-placeholder-verification-gate.md +104 -0
- package/template/.agent/skills/session-continuity/protocols/ambiguity-gates.md +48 -0
- package/template/.agent/skills/skill-creator/LICENSE.txt +202 -0
- package/template/.agent/skills/skill-creator/README.md +270 -0
- package/template/.agent/skills/skill-creator/SKILL.md +590 -0
- package/template/.agent/skills/skill-creator/references/output-patterns.md +82 -0
- package/template/.agent/skills/skill-creator/references/workflows.md +28 -0
- package/template/.agent/skills/skill-creator/scripts/init_skill.py +303 -0
- package/template/.agent/skills/skill-creator/scripts/package_skill.py +110 -0
- package/template/.agent/skills/skill-creator/scripts/quick_validate.py +95 -0
- package/template/.agent/skills/spec-writing/SKILL.md +110 -0
- package/template/.agent/skills/systematic-debugging/CREATION-LOG.md +119 -0
- package/template/.agent/skills/systematic-debugging/SKILL.md +297 -0
- package/template/.agent/skills/systematic-debugging/condition-based-waiting-example.ts +158 -0
- package/template/.agent/skills/systematic-debugging/condition-based-waiting.md +115 -0
- package/template/.agent/skills/systematic-debugging/defense-in-depth.md +122 -0
- package/template/.agent/skills/systematic-debugging/find-polluter.sh +63 -0
- package/template/.agent/skills/systematic-debugging/root-cause-tracing.md +169 -0
- package/template/.agent/skills/systematic-debugging/test-academic.md +14 -0
- package/template/.agent/skills/systematic-debugging/test-pressure-1.md +58 -0
- package/template/.agent/skills/systematic-debugging/test-pressure-2.md +68 -0
- package/template/.agent/skills/systematic-debugging/test-pressure-3.md +69 -0
- package/template/.agent/skills/tdd-workflow/SKILL.md +409 -0
- package/template/.agent/skills/tech-stack-catalog/SKILL.md +49 -0
- package/template/.agent/skills/tech-stack-catalog/references/constraint-questions.md +21 -0
- package/template/.agent/skills/tech-stack-catalog/references/dev-tooling-decisions.md +37 -0
- package/template/.agent/skills/tech-stack-catalog/references/surface-decision-tables.md +69 -0
- package/template/.agent/skills/technical-writer/SKILL.md +242 -0
- package/template/.agent/skills/testing-strategist/SKILL.md +932 -0
- package/template/.agent/skills/verification-before-completion/SKILL.md +145 -0
- package/template/.agent/skills/workflow-automation/SKILL.md +73 -0
- package/template/.agent/workflows/audit-ambiguity-execute.md +165 -0
- package/template/.agent/workflows/audit-ambiguity-rubrics.md +83 -0
- package/template/.agent/workflows/audit-ambiguity.md +64 -0
- package/template/.agent/workflows/bootstrap-agents-fill.md +201 -0
- package/template/.agent/workflows/bootstrap-agents-provision.md +197 -0
- package/template/.agent/workflows/bootstrap-agents.md +66 -0
- package/template/.agent/workflows/create-prd-architecture.md +119 -0
- package/template/.agent/workflows/create-prd-compile.md +138 -0
- package/template/.agent/workflows/create-prd-design-system.md +135 -0
- package/template/.agent/workflows/create-prd-security.md +113 -0
- package/template/.agent/workflows/create-prd-stack.md +91 -0
- package/template/.agent/workflows/create-prd.md +168 -0
- package/template/.agent/workflows/decompose-architecture-structure.md +82 -0
- package/template/.agent/workflows/decompose-architecture-validate.md +119 -0
- package/template/.agent/workflows/decompose-architecture.md +111 -0
- package/template/.agent/workflows/evolve-contract.md +98 -0
- package/template/.agent/workflows/evolve-feature-cascade.md +140 -0
- package/template/.agent/workflows/evolve-feature-classify.md +116 -0
- package/template/.agent/workflows/evolve-feature.md +56 -0
- package/template/.agent/workflows/ideate-discover.md +144 -0
- package/template/.agent/workflows/ideate-extract.md +129 -0
- package/template/.agent/workflows/ideate-validate.md +117 -0
- package/template/.agent/workflows/ideate.md +113 -0
- package/template/.agent/workflows/implement-slice-setup.md +113 -0
- package/template/.agent/workflows/implement-slice-tdd.md +198 -0
- package/template/.agent/workflows/implement-slice.md +50 -0
- package/template/.agent/workflows/plan-phase.md +202 -0
- package/template/.agent/workflows/propagate-decision-apply.md +135 -0
- package/template/.agent/workflows/propagate-decision-scan.md +147 -0
- package/template/.agent/workflows/propagate-decision.md +56 -0
- package/template/.agent/workflows/remediate-pipeline-assess.md +138 -0
- package/template/.agent/workflows/remediate-pipeline-execute.md +135 -0
- package/template/.agent/workflows/remediate-pipeline.md +55 -0
- package/template/.agent/workflows/resolve-ambiguity.md +82 -0
- package/template/.agent/workflows/sync-kit.md +209 -0
- package/template/.agent/workflows/update-architecture-map.md +74 -0
- package/template/.agent/workflows/validate-phase.md +219 -0
- package/template/.agent/workflows/verify-infrastructure.md +207 -0
- package/template/.agent/workflows/write-architecture-spec-deepen.md +139 -0
- package/template/.agent/workflows/write-architecture-spec-design.md +202 -0
- package/template/.agent/workflows/write-architecture-spec.md +63 -0
- package/template/.agent/workflows/write-be-spec-classify.md +165 -0
- package/template/.agent/workflows/write-be-spec-write.md +98 -0
- package/template/.agent/workflows/write-be-spec.md +76 -0
- package/template/.agent/workflows/write-fe-spec-classify.md +170 -0
- package/template/.agent/workflows/write-fe-spec-write.md +94 -0
- package/template/.agent/workflows/write-fe-spec.md +71 -0
- package/template/AGENTS.md +176 -0
- package/template/GEMINI.md +177 -0
- package/template/docs/README.md +187 -0
- package/template/docs/audits/.gitkeep +0 -0
- package/template/docs/audits/README.md +10 -0
- package/template/docs/plans/.gitkeep +0 -0
- package/template/docs/plans/README.md +21 -0
- package/template/docs/plans/be/.gitkeep +0 -0
- package/template/docs/plans/be/README.md +11 -0
- package/template/docs/plans/fe/.gitkeep +0 -0
- package/template/docs/plans/fe/README.md +11 -0
- package/template/docs/plans/ia/.gitkeep +0 -0
- package/template/docs/plans/ia/README.md +17 -0
- package/template/docs/plans/ia/deep-dives/.gitkeep +0 -0
- package/template/docs/plans/ia/deep-dives/README.md +5 -0
- package/template/docs/plans/phases/.gitkeep +0 -0
- package/template/docs/plans/phases/README.md +11 -0
|
@@ -0,0 +1,530 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: authentication-ui-flows
|
|
3
|
+
description: "Design and implement authentication user interfaces including login, registration, password reset, MFA, OAuth consent, session expiry, and account linking flows. Use when building auth pages, login forms, or user onboarding."
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Authentication UI Flows
|
|
8
|
+
|
|
9
|
+
Authentication is the front door of your application. These patterns ensure a secure, accessible, and user-friendly auth experience.
|
|
10
|
+
|
|
11
|
+
## Login Page
|
|
12
|
+
|
|
13
|
+
### Standard Email + Password
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
function LoginPage() {
|
|
17
|
+
const { register, handleSubmit, formState: { errors, isSubmitting }, setError } = useForm({
|
|
18
|
+
resolver: zodResolver(LoginSchema),
|
|
19
|
+
mode: 'onBlur',
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
const onSubmit = async (data: LoginFormData) => {
|
|
23
|
+
const result = await signIn(data.email, data.password);
|
|
24
|
+
if (!result.success) {
|
|
25
|
+
// SECURITY: Never reveal whether email exists or password is wrong
|
|
26
|
+
setError('root', { message: 'Invalid email or password' });
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
// Redirect to intended destination or dashboard
|
|
30
|
+
window.location.href = result.redirectTo ?? '/dashboard';
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<main className="auth-layout">
|
|
35
|
+
<div className="auth-card">
|
|
36
|
+
<h1>Sign in</h1>
|
|
37
|
+
|
|
38
|
+
{errors.root && (
|
|
39
|
+
<div role="alert" className="auth-error">{errors.root.message}</div>
|
|
40
|
+
)}
|
|
41
|
+
|
|
42
|
+
<form onSubmit={handleSubmit(onSubmit)} noValidate>
|
|
43
|
+
<div className="field-group">
|
|
44
|
+
<label htmlFor="email">Email address</label>
|
|
45
|
+
<input id="email" type="email" autoComplete="username"
|
|
46
|
+
aria-invalid={!!errors.email}
|
|
47
|
+
aria-describedby={errors.email ? 'email-error' : undefined}
|
|
48
|
+
{...register('email')} />
|
|
49
|
+
{errors.email && <p id="email-error" className="field-error">{errors.email.message}</p>}
|
|
50
|
+
</div>
|
|
51
|
+
|
|
52
|
+
<div className="field-group">
|
|
53
|
+
<label htmlFor="password">Password</label>
|
|
54
|
+
<input id="password" type="password" autoComplete="current-password"
|
|
55
|
+
aria-invalid={!!errors.password}
|
|
56
|
+
{...register('password')} />
|
|
57
|
+
<a href="/forgot-password" className="field-link">Forgot password?</a>
|
|
58
|
+
</div>
|
|
59
|
+
|
|
60
|
+
<label className="checkbox-label">
|
|
61
|
+
<input type="checkbox" {...register('rememberMe')} />
|
|
62
|
+
Remember me for 30 days
|
|
63
|
+
</label>
|
|
64
|
+
|
|
65
|
+
<button type="submit" disabled={isSubmitting} aria-busy={isSubmitting}>
|
|
66
|
+
{isSubmitting ? 'Signing in...' : 'Sign in'}
|
|
67
|
+
</button>
|
|
68
|
+
</form>
|
|
69
|
+
|
|
70
|
+
<div className="auth-divider" role="separator">
|
|
71
|
+
<span>or continue with</span>
|
|
72
|
+
</div>
|
|
73
|
+
|
|
74
|
+
<div className="social-buttons">
|
|
75
|
+
<button type="button" onClick={() => signInWithProvider('google')}>
|
|
76
|
+
<GoogleIcon aria-hidden="true" /> Sign in with Google
|
|
77
|
+
</button>
|
|
78
|
+
<button type="button" onClick={() => signInWithProvider('github')}>
|
|
79
|
+
<GitHubIcon aria-hidden="true" /> Sign in with GitHub
|
|
80
|
+
</button>
|
|
81
|
+
</div>
|
|
82
|
+
|
|
83
|
+
<p className="auth-footer">
|
|
84
|
+
Don't have an account? <a href="/register">Create one</a>
|
|
85
|
+
</p>
|
|
86
|
+
</div>
|
|
87
|
+
</main>
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Security Rules for Login UI
|
|
93
|
+
|
|
94
|
+
| Rule | Implementation |
|
|
95
|
+
|------|---------------|
|
|
96
|
+
| No username enumeration | Always say "Invalid email or password" regardless of which is wrong |
|
|
97
|
+
| Timing-safe feedback | Server response time must not differ between valid/invalid email |
|
|
98
|
+
| Rate limit feedback | After N failures: "Too many attempts. Try again in X minutes." |
|
|
99
|
+
| CAPTCHA placement | Show CAPTCHA after 3 failed attempts, not on first visit |
|
|
100
|
+
| No password in URL | Use POST, never GET with password in query string |
|
|
101
|
+
| HTTPS only | Redirect HTTP to HTTPS, set HSTS header |
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## Registration Flow
|
|
106
|
+
|
|
107
|
+
### Progressive Profiling
|
|
108
|
+
|
|
109
|
+
Collect only what you need upfront. Ask for details later.
|
|
110
|
+
|
|
111
|
+
**Step 1: Essentials only**
|
|
112
|
+
```typescript
|
|
113
|
+
const RegistrationStep1Schema = z.object({
|
|
114
|
+
email: z.string().email('Please enter a valid email'),
|
|
115
|
+
password: z.string()
|
|
116
|
+
.min(8, 'At least 8 characters')
|
|
117
|
+
.regex(/[A-Z]/, 'At least one uppercase letter')
|
|
118
|
+
.regex(/[0-9]/, 'At least one number'),
|
|
119
|
+
confirmPassword: z.string(),
|
|
120
|
+
acceptTerms: z.literal(true, {
|
|
121
|
+
errorMap: () => ({ message: 'You must accept the terms of service' }),
|
|
122
|
+
}),
|
|
123
|
+
}).refine((data) => data.password === data.confirmPassword, {
|
|
124
|
+
message: 'Passwords do not match',
|
|
125
|
+
path: ['confirmPassword'],
|
|
126
|
+
});
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
**Password strength indicator:**
|
|
130
|
+
```tsx
|
|
131
|
+
function PasswordStrength({ password }: { password: string }) {
|
|
132
|
+
const checks = [
|
|
133
|
+
{ label: 'At least 8 characters', met: password.length >= 8 },
|
|
134
|
+
{ label: 'One uppercase letter', met: /[A-Z]/.test(password) },
|
|
135
|
+
{ label: 'One number', met: /[0-9]/.test(password) },
|
|
136
|
+
{ label: 'One special character', met: /[^A-Za-z0-9]/.test(password) },
|
|
137
|
+
];
|
|
138
|
+
|
|
139
|
+
const strength = checks.filter((c) => c.met).length;
|
|
140
|
+
const strengthLabel = ['Weak', 'Weak', 'Fair', 'Good', 'Strong'][strength];
|
|
141
|
+
|
|
142
|
+
return (
|
|
143
|
+
<div aria-label={`Password strength: ${strengthLabel}`} role="status">
|
|
144
|
+
<div className="strength-bar">
|
|
145
|
+
<div className="strength-fill" style={{ width: `${(strength / 4) * 100}%` }}
|
|
146
|
+
data-strength={strengthLabel.toLowerCase()} />
|
|
147
|
+
</div>
|
|
148
|
+
<ul className="strength-checks" aria-label="Password requirements">
|
|
149
|
+
{checks.map((check) => (
|
|
150
|
+
<li key={check.label} aria-label={`${check.label}: ${check.met ? 'met' : 'not met'}`}>
|
|
151
|
+
{check.met ? '\u2713' : '\u2717'} {check.label}
|
|
152
|
+
</li>
|
|
153
|
+
))}
|
|
154
|
+
</ul>
|
|
155
|
+
</div>
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Email Verification
|
|
161
|
+
|
|
162
|
+
```tsx
|
|
163
|
+
function EmailVerificationPage() {
|
|
164
|
+
const [status, setStatus] = useState<'pending' | 'verified' | 'expired' | 'error'>('pending');
|
|
165
|
+
|
|
166
|
+
return (
|
|
167
|
+
<main className="auth-layout">
|
|
168
|
+
<div className="auth-card">
|
|
169
|
+
{status === 'pending' && (
|
|
170
|
+
<>
|
|
171
|
+
<h1>Check your email</h1>
|
|
172
|
+
<p>We sent a verification link to <strong>{email}</strong>.</p>
|
|
173
|
+
<p>Click the link in the email to verify your account.</p>
|
|
174
|
+
<button type="button" onClick={resendVerification} disabled={cooldown > 0}>
|
|
175
|
+
{cooldown > 0 ? `Resend in ${cooldown}s` : 'Resend verification email'}
|
|
176
|
+
</button>
|
|
177
|
+
<p className="hint">Check your spam folder if you don't see the email.</p>
|
|
178
|
+
</>
|
|
179
|
+
)}
|
|
180
|
+
|
|
181
|
+
{status === 'verified' && (
|
|
182
|
+
<>
|
|
183
|
+
<h1>Email verified</h1>
|
|
184
|
+
<p>Your account is ready. <a href="/login">Sign in</a></p>
|
|
185
|
+
</>
|
|
186
|
+
)}
|
|
187
|
+
|
|
188
|
+
{status === 'expired' && (
|
|
189
|
+
<>
|
|
190
|
+
<h1>Link expired</h1>
|
|
191
|
+
<p>This verification link has expired.</p>
|
|
192
|
+
<button type="button" onClick={resendVerification}>Send a new link</button>
|
|
193
|
+
</>
|
|
194
|
+
)}
|
|
195
|
+
</div>
|
|
196
|
+
</main>
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
---
|
|
202
|
+
|
|
203
|
+
## Password Reset Flow
|
|
204
|
+
|
|
205
|
+
### Step 1: Request Reset
|
|
206
|
+
|
|
207
|
+
```tsx
|
|
208
|
+
function ForgotPasswordPage() {
|
|
209
|
+
const [submitted, setSubmitted] = useState(false);
|
|
210
|
+
|
|
211
|
+
// SECURITY: Always show success message, even if email does not exist
|
|
212
|
+
return submitted ? (
|
|
213
|
+
<div className="auth-card">
|
|
214
|
+
<h1>Check your email</h1>
|
|
215
|
+
<p>If an account exists with that email, we sent a password reset link.</p>
|
|
216
|
+
<p className="hint">The link expires in 1 hour.</p>
|
|
217
|
+
</div>
|
|
218
|
+
) : (
|
|
219
|
+
<div className="auth-card">
|
|
220
|
+
<h1>Reset your password</h1>
|
|
221
|
+
<p>Enter your email and we'll send a reset link.</p>
|
|
222
|
+
<form onSubmit={handleSubmit}>
|
|
223
|
+
<label htmlFor="email">Email address</label>
|
|
224
|
+
<input id="email" type="email" autoComplete="username" required />
|
|
225
|
+
<button type="submit">Send reset link</button>
|
|
226
|
+
</form>
|
|
227
|
+
<a href="/login">Back to sign in</a>
|
|
228
|
+
</div>
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### Step 2: Set New Password
|
|
234
|
+
|
|
235
|
+
```tsx
|
|
236
|
+
function ResetPasswordPage({ token }: { token: string }) {
|
|
237
|
+
return (
|
|
238
|
+
<div className="auth-card">
|
|
239
|
+
<h1>Set a new password</h1>
|
|
240
|
+
<form onSubmit={handleSubmit}>
|
|
241
|
+
{/* Hidden email for password manager association */}
|
|
242
|
+
<input type="hidden" autoComplete="username" value={email} />
|
|
243
|
+
|
|
244
|
+
<label htmlFor="password">New password</label>
|
|
245
|
+
<input id="password" type="password" autoComplete="new-password" />
|
|
246
|
+
<PasswordStrength password={watchedPassword} />
|
|
247
|
+
|
|
248
|
+
<label htmlFor="confirmPassword">Confirm new password</label>
|
|
249
|
+
<input id="confirmPassword" type="password" autoComplete="new-password" />
|
|
250
|
+
|
|
251
|
+
<button type="submit">Reset password</button>
|
|
252
|
+
</form>
|
|
253
|
+
</div>
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## MFA Enrollment and Challenge
|
|
261
|
+
|
|
262
|
+
### MFA Enrollment
|
|
263
|
+
|
|
264
|
+
```tsx
|
|
265
|
+
function MFAEnrollmentPage() {
|
|
266
|
+
const [method, setMethod] = useState<'totp' | 'sms' | null>(null);
|
|
267
|
+
|
|
268
|
+
return (
|
|
269
|
+
<div className="auth-card">
|
|
270
|
+
<h1>Set up two-factor authentication</h1>
|
|
271
|
+
|
|
272
|
+
{!method && (
|
|
273
|
+
<div className="mfa-method-picker">
|
|
274
|
+
<button onClick={() => setMethod('totp')}>
|
|
275
|
+
<AuthenticatorIcon aria-hidden="true" />
|
|
276
|
+
<span>Authenticator app</span>
|
|
277
|
+
<span className="hint">Recommended</span>
|
|
278
|
+
</button>
|
|
279
|
+
<button onClick={() => setMethod('sms')}>
|
|
280
|
+
<PhoneIcon aria-hidden="true" />
|
|
281
|
+
<span>Text message (SMS)</span>
|
|
282
|
+
</button>
|
|
283
|
+
</div>
|
|
284
|
+
)}
|
|
285
|
+
|
|
286
|
+
{method === 'totp' && (
|
|
287
|
+
<>
|
|
288
|
+
<p>Scan this QR code with your authenticator app:</p>
|
|
289
|
+
<img src={qrCodeUrl} alt="QR code for authenticator app setup" />
|
|
290
|
+
<details>
|
|
291
|
+
<summary>Can't scan? Enter the key manually</summary>
|
|
292
|
+
<code className="manual-key" aria-label="Manual setup key">{secretKey}</code>
|
|
293
|
+
</details>
|
|
294
|
+
<label htmlFor="totp-code">Enter the 6-digit code from your app</label>
|
|
295
|
+
<input id="totp-code" type="text" inputMode="numeric" autoComplete="one-time-code"
|
|
296
|
+
pattern="[0-9]{6}" maxLength={6} />
|
|
297
|
+
<button type="submit">Verify and enable</button>
|
|
298
|
+
</>
|
|
299
|
+
)}
|
|
300
|
+
</div>
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### MFA Challenge
|
|
306
|
+
|
|
307
|
+
```tsx
|
|
308
|
+
function MFAChallengeModal() {
|
|
309
|
+
return (
|
|
310
|
+
<div role="dialog" aria-labelledby="mfa-title" aria-modal="true">
|
|
311
|
+
<h2 id="mfa-title">Two-factor authentication</h2>
|
|
312
|
+
<p>Enter the 6-digit code from your authenticator app.</p>
|
|
313
|
+
|
|
314
|
+
<form onSubmit={handleVerify}>
|
|
315
|
+
<label htmlFor="mfa-code" className="visually-hidden">Authentication code</label>
|
|
316
|
+
<input id="mfa-code" type="text" inputMode="numeric"
|
|
317
|
+
autoComplete="one-time-code" autoFocus
|
|
318
|
+
pattern="[0-9]{6}" maxLength={6}
|
|
319
|
+
aria-describedby="mfa-hint" />
|
|
320
|
+
<p id="mfa-hint" className="hint">Open your authenticator app to find the code.</p>
|
|
321
|
+
|
|
322
|
+
<button type="submit" disabled={isVerifying}>
|
|
323
|
+
{isVerifying ? 'Verifying...' : 'Verify'}
|
|
324
|
+
</button>
|
|
325
|
+
</form>
|
|
326
|
+
|
|
327
|
+
<button type="button" onClick={switchToRecoveryCode} className="link-button">
|
|
328
|
+
Use a recovery code instead
|
|
329
|
+
</button>
|
|
330
|
+
</div>
|
|
331
|
+
);
|
|
332
|
+
}
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
---
|
|
336
|
+
|
|
337
|
+
## Session Expiry Handling
|
|
338
|
+
|
|
339
|
+
### Silent Refresh
|
|
340
|
+
|
|
341
|
+
```typescript
|
|
342
|
+
// Refresh token before it expires
|
|
343
|
+
function setupTokenRefresh(expiresAt: number): void {
|
|
344
|
+
const refreshBuffer = 60_000; // Refresh 1 minute before expiry
|
|
345
|
+
const timeout = expiresAt - Date.now() - refreshBuffer;
|
|
346
|
+
|
|
347
|
+
if (timeout <= 0) {
|
|
348
|
+
refreshToken();
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
setTimeout(async () => {
|
|
353
|
+
const result = await refreshToken();
|
|
354
|
+
if (result.success) {
|
|
355
|
+
setupTokenRefresh(result.expiresAt);
|
|
356
|
+
} else {
|
|
357
|
+
showSessionExpiredModal();
|
|
358
|
+
}
|
|
359
|
+
}, timeout);
|
|
360
|
+
}
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
### Session Expired Modal
|
|
364
|
+
|
|
365
|
+
```tsx
|
|
366
|
+
function SessionExpiredModal() {
|
|
367
|
+
return (
|
|
368
|
+
<div role="alertdialog" aria-labelledby="session-title" aria-describedby="session-desc" aria-modal="true">
|
|
369
|
+
<h2 id="session-title">Session expired</h2>
|
|
370
|
+
<p id="session-desc">Your session has expired. Sign in again to continue.</p>
|
|
371
|
+
<div className="modal-actions">
|
|
372
|
+
<button onClick={() => redirectToLogin({ returnTo: window.location.pathname })}>
|
|
373
|
+
Sign in
|
|
374
|
+
</button>
|
|
375
|
+
</div>
|
|
376
|
+
</div>
|
|
377
|
+
);
|
|
378
|
+
}
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
---
|
|
382
|
+
|
|
383
|
+
## "Remember Me" UX
|
|
384
|
+
|
|
385
|
+
| Option | Session Duration | Implementation |
|
|
386
|
+
|--------|-----------------|----------------|
|
|
387
|
+
| Unchecked | Browser session (closes on tab close) | Session cookie (no `max-age`) |
|
|
388
|
+
| Checked | 30 days | Persistent cookie with `max-age=2592000` |
|
|
389
|
+
|
|
390
|
+
**Security considerations:**
|
|
391
|
+
- "Remember me" should extend the refresh token lifetime, not remove re-authentication for sensitive actions
|
|
392
|
+
- Sensitive actions (change password, add payment) should always require recent authentication regardless of "remember me"
|
|
393
|
+
|
|
394
|
+
---
|
|
395
|
+
|
|
396
|
+
## Account Linking
|
|
397
|
+
|
|
398
|
+
```tsx
|
|
399
|
+
function LinkedAccountsSettings() {
|
|
400
|
+
const linkedProviders = useLinkedProviders();
|
|
401
|
+
|
|
402
|
+
return (
|
|
403
|
+
<section>
|
|
404
|
+
<h2>Linked accounts</h2>
|
|
405
|
+
<p>Sign in with any of these providers.</p>
|
|
406
|
+
|
|
407
|
+
<ul className="provider-list">
|
|
408
|
+
{providers.map((provider) => {
|
|
409
|
+
const isLinked = linkedProviders.includes(provider.id);
|
|
410
|
+
return (
|
|
411
|
+
<li key={provider.id}>
|
|
412
|
+
<provider.icon aria-hidden="true" />
|
|
413
|
+
<span>{provider.name}</span>
|
|
414
|
+
{isLinked ? (
|
|
415
|
+
<button onClick={() => unlinkProvider(provider.id)}
|
|
416
|
+
aria-label={`Unlink ${provider.name} account`}>
|
|
417
|
+
Unlink
|
|
418
|
+
</button>
|
|
419
|
+
) : (
|
|
420
|
+
<button onClick={() => linkProvider(provider.id)}
|
|
421
|
+
aria-label={`Link ${provider.name} account`}>
|
|
422
|
+
Link
|
|
423
|
+
</button>
|
|
424
|
+
)}
|
|
425
|
+
</li>
|
|
426
|
+
);
|
|
427
|
+
})}
|
|
428
|
+
</ul>
|
|
429
|
+
|
|
430
|
+
<p className="hint">You must keep at least one sign-in method active.</p>
|
|
431
|
+
</section>
|
|
432
|
+
);
|
|
433
|
+
}
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
---
|
|
437
|
+
|
|
438
|
+
## Error States
|
|
439
|
+
|
|
440
|
+
| Error | User-Facing Message | Notes |
|
|
441
|
+
|-------|---------------------|-------|
|
|
442
|
+
| Invalid credentials | "Invalid email or password" | Never reveal which field is wrong |
|
|
443
|
+
| Account locked | "Account locked. Check email for unlock instructions." | After N failed attempts |
|
|
444
|
+
| Rate limited | "Too many attempts. Try again in 15 minutes." | Show countdown timer |
|
|
445
|
+
| Email not verified | "Please verify your email. [Resend link]" | Include resend action |
|
|
446
|
+
| OAuth error | "Sign in with [Provider] failed. Try again or use email." | Offer alternative |
|
|
447
|
+
| Network error | "Connection problem. Check your internet and try again." | Offer retry |
|
|
448
|
+
| Token expired | "This link has expired. [Request a new one]" | Password reset, verification |
|
|
449
|
+
| Server error | "Something went wrong on our end. Try again shortly." | Log details server-side |
|
|
450
|
+
|
|
451
|
+
---
|
|
452
|
+
|
|
453
|
+
## Mobile-Responsive Auth Layouts
|
|
454
|
+
|
|
455
|
+
```css
|
|
456
|
+
.auth-layout {
|
|
457
|
+
display: flex;
|
|
458
|
+
align-items: center;
|
|
459
|
+
justify-content: center;
|
|
460
|
+
min-height: 100dvh;
|
|
461
|
+
padding: 1rem;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
.auth-card {
|
|
465
|
+
width: 100%;
|
|
466
|
+
max-width: 420px;
|
|
467
|
+
padding: 2rem;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/* On mobile, auth card fills the screen */
|
|
471
|
+
@media (max-width: 480px) {
|
|
472
|
+
.auth-layout {
|
|
473
|
+
align-items: flex-start;
|
|
474
|
+
padding: 0;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
.auth-card {
|
|
478
|
+
max-width: none;
|
|
479
|
+
min-height: 100dvh;
|
|
480
|
+
padding: 1.5rem;
|
|
481
|
+
border-radius: 0;
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/* Inputs should be at least 44px tall for touch targets */
|
|
486
|
+
.auth-card input,
|
|
487
|
+
.auth-card button,
|
|
488
|
+
.auth-card select {
|
|
489
|
+
min-height: 44px;
|
|
490
|
+
font-size: 1rem; /* Prevents iOS zoom on focus */
|
|
491
|
+
}
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
---
|
|
495
|
+
|
|
496
|
+
## Loading States
|
|
497
|
+
|
|
498
|
+
```tsx
|
|
499
|
+
function AuthSkeleton() {
|
|
500
|
+
return (
|
|
501
|
+
<div className="auth-card" aria-busy="true" aria-label="Loading authentication form">
|
|
502
|
+
<div className="skeleton skeleton-title" />
|
|
503
|
+
<div className="skeleton skeleton-input" />
|
|
504
|
+
<div className="skeleton skeleton-input" />
|
|
505
|
+
<div className="skeleton skeleton-button" />
|
|
506
|
+
</div>
|
|
507
|
+
);
|
|
508
|
+
}
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
---
|
|
512
|
+
|
|
513
|
+
## Anti-Patterns
|
|
514
|
+
|
|
515
|
+
| Anti-Pattern | Correct Approach |
|
|
516
|
+
|-------------|------------------|
|
|
517
|
+
| "Email not found" on login | "Invalid email or password" (timing-safe) |
|
|
518
|
+
| Password visible in URL params | POST request body only |
|
|
519
|
+
| Auto-redirect after login without checking destination | Validate redirect URL is same-origin |
|
|
520
|
+
| Showing CAPTCHA on first visit | Show after 3 failed attempts |
|
|
521
|
+
| Infinite session with no re-auth | Require re-auth for sensitive actions |
|
|
522
|
+
| OAuth popup without fallback | Support redirect flow for popup blockers |
|
|
523
|
+
| Storing tokens in localStorage | Use httpOnly cookies for tokens |
|
|
524
|
+
| Magic link that never expires | Expire in 15 minutes, single-use |
|
|
525
|
+
|
|
526
|
+
## References
|
|
527
|
+
|
|
528
|
+
- [OWASP Authentication Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html)
|
|
529
|
+
- [NIST Digital Identity Guidelines](https://pages.nist.gov/800-63-3/)
|
|
530
|
+
- [WAI Forms Tutorial](https://www.w3.org/WAI/tutorials/forms/)
|