@jaimevalasek/aioson 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (288) hide show
  1. package/CHANGELOG.md +456 -0
  2. package/CODE_OF_CONDUCT.md +12 -0
  3. package/CONTRIBUTING.md +13 -0
  4. package/LICENSE +21 -0
  5. package/README.md +254 -0
  6. package/bin/aioson.js +4 -0
  7. package/docs/en/cli-reference.md +398 -0
  8. package/docs/en/i18n.md +52 -0
  9. package/docs/en/json-schemas.md +41 -0
  10. package/docs/en/mcp.md +56 -0
  11. package/docs/en/parallel.md +82 -0
  12. package/docs/en/qa-browser.md +339 -0
  13. package/docs/en/release-flow.md +22 -0
  14. package/docs/en/release-notes-template.md +41 -0
  15. package/docs/en/release.md +28 -0
  16. package/docs/en/schemas/agent-prompt.schema.json +17 -0
  17. package/docs/en/schemas/agents.schema.json +32 -0
  18. package/docs/en/schemas/context-validate.schema.json +36 -0
  19. package/docs/en/schemas/doctor.schema.json +89 -0
  20. package/docs/en/schemas/error.schema.json +24 -0
  21. package/docs/en/schemas/i18n-add.schema.json +15 -0
  22. package/docs/en/schemas/index.json +116 -0
  23. package/docs/en/schemas/info.schema.json +39 -0
  24. package/docs/en/schemas/init.schema.json +48 -0
  25. package/docs/en/schemas/install.schema.json +60 -0
  26. package/docs/en/schemas/locale-apply.schema.json +30 -0
  27. package/docs/en/schemas/mcp-doctor.schema.json +95 -0
  28. package/docs/en/schemas/mcp-init.schema.json +122 -0
  29. package/docs/en/schemas/package-test.schema.json +24 -0
  30. package/docs/en/schemas/parallel-assign.schema.json +57 -0
  31. package/docs/en/schemas/parallel-doctor.schema.json +86 -0
  32. package/docs/en/schemas/parallel-init.schema.json +53 -0
  33. package/docs/en/schemas/parallel-status.schema.json +94 -0
  34. package/docs/en/schemas/setup-context.schema.json +39 -0
  35. package/docs/en/schemas/smoke.schema.json +23 -0
  36. package/docs/en/schemas/update.schema.json +48 -0
  37. package/docs/en/schemas/workflow-plan.schema.json +30 -0
  38. package/docs/en/web3.md +54 -0
  39. package/docs/pt/README.md +46 -0
  40. package/docs/pt/advisor-spec.md +335 -0
  41. package/docs/pt/agentes.md +453 -0
  42. package/docs/pt/cenarios.md +1230 -0
  43. package/docs/pt/clientes-ai.md +224 -0
  44. package/docs/pt/comandos-cli.md +511 -0
  45. package/docs/pt/genome-3.0-spec.md +296 -0
  46. package/docs/pt/guia-engineer.md +226 -0
  47. package/docs/pt/inicio-rapido.md +138 -0
  48. package/docs/pt/profiler-system.md +214 -0
  49. package/docs/pt/runtime-observability.md +72 -0
  50. package/docs/pt/squad-genoma.md +777 -0
  51. package/docs/pt/web3.md +797 -0
  52. package/docs/testing/genome-2.0-manual-regression.md +23 -0
  53. package/docs/testing/genome-2.0-matrix.md +36 -0
  54. package/docs/testing/genome-2.0-rollout.md +184 -0
  55. package/package.json +50 -0
  56. package/src/agents.js +56 -0
  57. package/src/cli.js +497 -0
  58. package/src/commands/agents.js +142 -0
  59. package/src/commands/cloud.js +1767 -0
  60. package/src/commands/config.js +90 -0
  61. package/src/commands/context-validate.js +91 -0
  62. package/src/commands/doctor.js +123 -0
  63. package/src/commands/genome-doctor.js +41 -0
  64. package/src/commands/genome-migrate.js +49 -0
  65. package/src/commands/i18n-add.js +56 -0
  66. package/src/commands/info.js +41 -0
  67. package/src/commands/init.js +75 -0
  68. package/src/commands/install.js +68 -0
  69. package/src/commands/locale-apply.js +51 -0
  70. package/src/commands/locale-diff.js +126 -0
  71. package/src/commands/mcp-doctor.js +406 -0
  72. package/src/commands/mcp-init.js +379 -0
  73. package/src/commands/package-e2e.js +273 -0
  74. package/src/commands/parallel-assign.js +403 -0
  75. package/src/commands/parallel-doctor.js +437 -0
  76. package/src/commands/parallel-init.js +249 -0
  77. package/src/commands/parallel-status.js +290 -0
  78. package/src/commands/qa-doctor.js +185 -0
  79. package/src/commands/qa-init.js +161 -0
  80. package/src/commands/qa-report.js +58 -0
  81. package/src/commands/qa-run.js +873 -0
  82. package/src/commands/qa-scan.js +337 -0
  83. package/src/commands/runtime.js +948 -0
  84. package/src/commands/scan-project.js +1107 -0
  85. package/src/commands/setup-context.js +650 -0
  86. package/src/commands/smoke.js +426 -0
  87. package/src/commands/squad-doctor.js +358 -0
  88. package/src/commands/squad-export.js +46 -0
  89. package/src/commands/squad-pipeline.js +97 -0
  90. package/src/commands/squad-repair-genomes.js +39 -0
  91. package/src/commands/squad-status.js +424 -0
  92. package/src/commands/squad-validate.js +230 -0
  93. package/src/commands/test-agents.js +194 -0
  94. package/src/commands/update.js +55 -0
  95. package/src/commands/workflow-next.js +594 -0
  96. package/src/commands/workflow-plan.js +108 -0
  97. package/src/constants.js +314 -0
  98. package/src/context-parse-reason.js +22 -0
  99. package/src/context-writer.js +150 -0
  100. package/src/context.js +217 -0
  101. package/src/detector.js +261 -0
  102. package/src/doctor.js +289 -0
  103. package/src/execution-gateway.js +461 -0
  104. package/src/genome-files.js +198 -0
  105. package/src/genome-format.js +442 -0
  106. package/src/genome-schema.js +215 -0
  107. package/src/genomes/bindings.js +281 -0
  108. package/src/genomes.js +467 -0
  109. package/src/i18n/index.js +103 -0
  110. package/src/i18n/messages/en.js +784 -0
  111. package/src/i18n/messages/es.js +718 -0
  112. package/src/i18n/messages/fr.js +725 -0
  113. package/src/i18n/messages/pt-BR.js +818 -0
  114. package/src/i18n/scaffold.js +64 -0
  115. package/src/installer.js +232 -0
  116. package/src/lib/genomes/compat.js +206 -0
  117. package/src/lib/genomes/migrate.js +90 -0
  118. package/src/lib/squads/genome-repair.js +49 -0
  119. package/src/locales.js +84 -0
  120. package/src/onboarding.js +305 -0
  121. package/src/parser.js +53 -0
  122. package/src/prompt-tool.js +20 -0
  123. package/src/qa-html-report.js +472 -0
  124. package/src/runtime-store.js +1527 -0
  125. package/src/squads/apply-genome.js +21 -0
  126. package/src/squads/genome-binding-service.js +154 -0
  127. package/src/updater.js +32 -0
  128. package/src/utils.js +46 -0
  129. package/src/version.js +50 -0
  130. package/template/.aioson/advisors/.gitkeep +1 -0
  131. package/template/.aioson/agents/analyst.md +225 -0
  132. package/template/.aioson/agents/architect.md +221 -0
  133. package/template/.aioson/agents/dev.md +201 -0
  134. package/template/.aioson/agents/discovery-design-doc.md +196 -0
  135. package/template/.aioson/agents/genoma.md +300 -0
  136. package/template/.aioson/agents/orchestrator.md +107 -0
  137. package/template/.aioson/agents/pm.md +89 -0
  138. package/template/.aioson/agents/product.md +361 -0
  139. package/template/.aioson/agents/profiler-enricher.md +266 -0
  140. package/template/.aioson/agents/profiler-forge.md +188 -0
  141. package/template/.aioson/agents/profiler-researcher.md +245 -0
  142. package/template/.aioson/agents/qa.md +344 -0
  143. package/template/.aioson/agents/setup.md +381 -0
  144. package/template/.aioson/agents/squad.md +837 -0
  145. package/template/.aioson/agents/ux-ui.md +416 -0
  146. package/template/.aioson/config.md +56 -0
  147. package/template/.aioson/context/.gitkeep +0 -0
  148. package/template/.aioson/context/parallel/.gitkeep +0 -0
  149. package/template/.aioson/context/spec.md.template +37 -0
  150. package/template/.aioson/genomas/.gitkeep +0 -0
  151. package/template/.aioson/locales/en/agents/analyst.md +214 -0
  152. package/template/.aioson/locales/en/agents/architect.md +210 -0
  153. package/template/.aioson/locales/en/agents/dev.md +187 -0
  154. package/template/.aioson/locales/en/agents/discovery-design-doc.md +27 -0
  155. package/template/.aioson/locales/en/agents/genoma.md +212 -0
  156. package/template/.aioson/locales/en/agents/orchestrator.md +105 -0
  157. package/template/.aioson/locales/en/agents/pm.md +77 -0
  158. package/template/.aioson/locales/en/agents/product.md +310 -0
  159. package/template/.aioson/locales/en/agents/profiler-enricher.md +5 -0
  160. package/template/.aioson/locales/en/agents/profiler-forge.md +5 -0
  161. package/template/.aioson/locales/en/agents/profiler-researcher.md +5 -0
  162. package/template/.aioson/locales/en/agents/qa.md +214 -0
  163. package/template/.aioson/locales/en/agents/setup.md +342 -0
  164. package/template/.aioson/locales/en/agents/squad.md +247 -0
  165. package/template/.aioson/locales/en/agents/ux-ui.md +320 -0
  166. package/template/.aioson/locales/es/agents/analyst.md +203 -0
  167. package/template/.aioson/locales/es/agents/architect.md +208 -0
  168. package/template/.aioson/locales/es/agents/dev.md +183 -0
  169. package/template/.aioson/locales/es/agents/discovery-design-doc.md +19 -0
  170. package/template/.aioson/locales/es/agents/genoma.md +102 -0
  171. package/template/.aioson/locales/es/agents/orchestrator.md +108 -0
  172. package/template/.aioson/locales/es/agents/pm.md +81 -0
  173. package/template/.aioson/locales/es/agents/product.md +310 -0
  174. package/template/.aioson/locales/es/agents/profiler-enricher.md +5 -0
  175. package/template/.aioson/locales/es/agents/profiler-forge.md +5 -0
  176. package/template/.aioson/locales/es/agents/profiler-researcher.md +5 -0
  177. package/template/.aioson/locales/es/agents/qa.md +163 -0
  178. package/template/.aioson/locales/es/agents/setup.md +347 -0
  179. package/template/.aioson/locales/es/agents/squad.md +247 -0
  180. package/template/.aioson/locales/es/agents/ux-ui.md +201 -0
  181. package/template/.aioson/locales/fr/agents/analyst.md +203 -0
  182. package/template/.aioson/locales/fr/agents/architect.md +208 -0
  183. package/template/.aioson/locales/fr/agents/dev.md +183 -0
  184. package/template/.aioson/locales/fr/agents/discovery-design-doc.md +19 -0
  185. package/template/.aioson/locales/fr/agents/genoma.md +102 -0
  186. package/template/.aioson/locales/fr/agents/orchestrator.md +108 -0
  187. package/template/.aioson/locales/fr/agents/pm.md +81 -0
  188. package/template/.aioson/locales/fr/agents/product.md +310 -0
  189. package/template/.aioson/locales/fr/agents/profiler-enricher.md +5 -0
  190. package/template/.aioson/locales/fr/agents/profiler-forge.md +5 -0
  191. package/template/.aioson/locales/fr/agents/profiler-researcher.md +5 -0
  192. package/template/.aioson/locales/fr/agents/qa.md +163 -0
  193. package/template/.aioson/locales/fr/agents/setup.md +347 -0
  194. package/template/.aioson/locales/fr/agents/squad.md +247 -0
  195. package/template/.aioson/locales/fr/agents/ux-ui.md +201 -0
  196. package/template/.aioson/locales/pt-BR/agents/analyst.md +217 -0
  197. package/template/.aioson/locales/pt-BR/agents/architect.md +213 -0
  198. package/template/.aioson/locales/pt-BR/agents/dev.md +198 -0
  199. package/template/.aioson/locales/pt-BR/agents/discovery-design-doc.md +198 -0
  200. package/template/.aioson/locales/pt-BR/agents/genoma.md +297 -0
  201. package/template/.aioson/locales/pt-BR/agents/orchestrator.md +108 -0
  202. package/template/.aioson/locales/pt-BR/agents/pm.md +81 -0
  203. package/template/.aioson/locales/pt-BR/agents/product.md +316 -0
  204. package/template/.aioson/locales/pt-BR/agents/profiler-enricher.md +5 -0
  205. package/template/.aioson/locales/pt-BR/agents/profiler-forge.md +5 -0
  206. package/template/.aioson/locales/pt-BR/agents/profiler-researcher.md +5 -0
  207. package/template/.aioson/locales/pt-BR/agents/qa.md +217 -0
  208. package/template/.aioson/locales/pt-BR/agents/setup.md +371 -0
  209. package/template/.aioson/locales/pt-BR/agents/squad.md +772 -0
  210. package/template/.aioson/locales/pt-BR/agents/ux-ui.md +322 -0
  211. package/template/.aioson/mcp/servers.md +24 -0
  212. package/template/.aioson/profiler-reports/.gitkeep +1 -0
  213. package/template/.aioson/schemas/content-blueprint.schema.json +30 -0
  214. package/template/.aioson/schemas/genome-meta.schema.json +150 -0
  215. package/template/.aioson/schemas/genome.schema.json +115 -0
  216. package/template/.aioson/schemas/readiness.schema.json +27 -0
  217. package/template/.aioson/schemas/squad-blueprint.schema.json +172 -0
  218. package/template/.aioson/schemas/squad-manifest.schema.json +276 -0
  219. package/template/.aioson/skills/dynamic/README.md +30 -0
  220. package/template/.aioson/skills/dynamic/cardano-docs.md +16 -0
  221. package/template/.aioson/skills/dynamic/ethereum-docs.md +17 -0
  222. package/template/.aioson/skills/dynamic/flux-ui-docs.md +13 -0
  223. package/template/.aioson/skills/dynamic/laravel-docs.md +41 -0
  224. package/template/.aioson/skills/dynamic/npm-packages.md +16 -0
  225. package/template/.aioson/skills/dynamic/solana-docs.md +16 -0
  226. package/template/.aioson/skills/references/premium-command-center-ui/master-application-prompt.md +79 -0
  227. package/template/.aioson/skills/references/premium-command-center-ui/operational-ux-playbook.md +253 -0
  228. package/template/.aioson/skills/references/premium-command-center-ui/quality-validation-checklist.md +82 -0
  229. package/template/.aioson/skills/references/premium-command-center-ui/visual-system-and-component-patterns.md +270 -0
  230. package/template/.aioson/skills/static/django-patterns.md +342 -0
  231. package/template/.aioson/skills/static/fastapi-patterns.md +344 -0
  232. package/template/.aioson/skills/static/filament-patterns.md +267 -0
  233. package/template/.aioson/skills/static/flux-ui-components.md +262 -0
  234. package/template/.aioson/skills/static/git-conventions.md +227 -0
  235. package/template/.aioson/skills/static/interface-design.md +372 -0
  236. package/template/.aioson/skills/static/jetstream-setup.md +200 -0
  237. package/template/.aioson/skills/static/laravel-conventions.md +491 -0
  238. package/template/.aioson/skills/static/nextjs-patterns.md +321 -0
  239. package/template/.aioson/skills/static/node-express-patterns.md +317 -0
  240. package/template/.aioson/skills/static/node-typescript-patterns.md +282 -0
  241. package/template/.aioson/skills/static/premium-command-center-ui.md +190 -0
  242. package/template/.aioson/skills/static/rails-conventions.md +307 -0
  243. package/template/.aioson/skills/static/react-motion-patterns.md +577 -0
  244. package/template/.aioson/skills/static/static-html-patterns.md +1935 -0
  245. package/template/.aioson/skills/static/tall-stack-patterns.md +286 -0
  246. package/template/.aioson/skills/static/ui-ux-modern.md +75 -0
  247. package/template/.aioson/skills/static/web3-cardano-patterns.md +337 -0
  248. package/template/.aioson/skills/static/web3-ethereum-patterns.md +310 -0
  249. package/template/.aioson/skills/static/web3-security-checklist.md +284 -0
  250. package/template/.aioson/skills/static/web3-solana-patterns.md +324 -0
  251. package/template/.aioson/squads/.artisan/.gitkeep +0 -0
  252. package/template/.aioson/squads/.gitkeep +0 -0
  253. package/template/.aioson/squads/memory.md +5 -0
  254. package/template/.aioson/tasks/squad-analyze.md +83 -0
  255. package/template/.aioson/tasks/squad-create.md +99 -0
  256. package/template/.aioson/tasks/squad-design.md +100 -0
  257. package/template/.aioson/tasks/squad-export.md +20 -0
  258. package/template/.aioson/tasks/squad-extend.md +68 -0
  259. package/template/.aioson/tasks/squad-pipeline.md +122 -0
  260. package/template/.aioson/tasks/squad-repair.md +85 -0
  261. package/template/.aioson/tasks/squad-validate.md +58 -0
  262. package/template/.aioson/templates/squads/content-basic/template.json +21 -0
  263. package/template/.aioson/templates/squads/media-channel/template.json +24 -0
  264. package/template/.aioson/templates/squads/research-analysis/template.json +22 -0
  265. package/template/.aioson/templates/squads/software-delivery/template.json +21 -0
  266. package/template/.claude/commands/aioson/analyst.md +5 -0
  267. package/template/.claude/commands/aioson/architect.md +5 -0
  268. package/template/.claude/commands/aioson/dev.md +5 -0
  269. package/template/.claude/commands/aioson/orchestrator.md +5 -0
  270. package/template/.claude/commands/aioson/pm.md +5 -0
  271. package/template/.claude/commands/aioson/qa.md +5 -0
  272. package/template/.claude/commands/aioson/setup.md +5 -0
  273. package/template/.claude/commands/aioson/ux-ui.md +5 -0
  274. package/template/.gemini/GEMINI.md +10 -0
  275. package/template/.gemini/commands/aios-analyst.toml +4 -0
  276. package/template/.gemini/commands/aios-architect.toml +7 -0
  277. package/template/.gemini/commands/aios-dev.toml +8 -0
  278. package/template/.gemini/commands/aios-discovery-design-doc.toml +4 -0
  279. package/template/.gemini/commands/aios-orchestrator.toml +8 -0
  280. package/template/.gemini/commands/aios-pm.toml +8 -0
  281. package/template/.gemini/commands/aios-product.toml +4 -0
  282. package/template/.gemini/commands/aios-qa.toml +6 -0
  283. package/template/.gemini/commands/aios-setup.toml +3 -0
  284. package/template/.gemini/commands/aios-ux-ui.toml +8 -0
  285. package/template/AGENTS.md +67 -0
  286. package/template/CLAUDE.md +31 -0
  287. package/template/OPENCODE.md +24 -0
  288. package/template/aioson-models.json +40 -0
@@ -0,0 +1,200 @@
1
+ # Jetstream Setup
2
+
3
+ > Laravel Jetstream scaffolds authentication, teams, API tokens, and profile management. Decide at project creation.
4
+
5
+ ---
6
+
7
+ ## Decision: Inertia vs Blade
8
+
9
+ Make this choice before `artisan jetstream:install` — it cannot be changed without reinstalling.
10
+
11
+ | Factor | Blade + Livewire | Inertia + Vue/React |
12
+ |---|---|---|
13
+ | Team skillset | PHP-first | JS-first |
14
+ | SPA behavior needed? | No | Yes |
15
+ | Existing Livewire investment? | Yes → Blade | No |
16
+ | Complex client-side state? | No | Yes |
17
+ | SEO critical? | Both work | Both work (with SSR) |
18
+
19
+ ---
20
+
21
+ ## Installation
22
+
23
+ ```bash
24
+ # Blade + Livewire (most common for TALL stack)
25
+ composer require laravel/jetstream
26
+ php artisan jetstream:install livewire --teams # omit --teams if not needed
27
+ npm install && npm run build
28
+ php artisan migrate
29
+
30
+ # Inertia + Vue
31
+ php artisan jetstream:install inertia --teams
32
+ npm install && npm run build
33
+ php artisan migrate
34
+ ```
35
+
36
+ ---
37
+
38
+ ## Teams — use only when multi-tenant is required
39
+
40
+ Teams give each user an isolated workspace. Enable only if your domain genuinely needs it.
41
+
42
+ ```php
43
+ // Check if the current user belongs to a team
44
+ auth()->user()->currentTeam->name;
45
+
46
+ // Add a custom field to teams
47
+ // database/migrations/xxxx_add_plan_to_teams.php
48
+ Schema::table('teams', function (Blueprint $table) {
49
+ $table->string('plan')->default('free');
50
+ $table->integer('member_limit')->default(3);
51
+ });
52
+
53
+ // Team model customization
54
+ // app/Models/Team.php
55
+ class Team extends JetstreamTeam
56
+ {
57
+ protected $fillable = ['name', 'personal_team', 'plan', 'member_limit'];
58
+
59
+ public function hasAvailableSlots(): bool
60
+ {
61
+ return $this->users()->count() < $this->member_limit;
62
+ }
63
+ }
64
+ ```
65
+
66
+ ---
67
+
68
+ ## Roles and permissions (Teams)
69
+
70
+ ```php
71
+ // Define in JetstreamServiceProvider
72
+ Jetstream::defaultApiTokenPermissions(['read']);
73
+
74
+ Jetstream::role('admin', 'Administrator', [
75
+ 'create', 'read', 'update', 'delete',
76
+ ])->description('Administrators have full control.');
77
+
78
+ Jetstream::role('editor', 'Editor', [
79
+ 'create', 'read', 'update',
80
+ ])->description('Editors can create and edit content.');
81
+
82
+ // Check in controllers
83
+ if (! $request->user()->hasTeamRole($team, 'admin')) {
84
+ abort(403);
85
+ }
86
+
87
+ // Check in Policies
88
+ public function update(User $user, Post $post): bool
89
+ {
90
+ return $user->hasTeamPermission($post->team, 'update');
91
+ }
92
+ ```
93
+
94
+ ---
95
+
96
+ ## API tokens
97
+
98
+ ```php
99
+ // Token creation is built-in via Jetstream UI
100
+ // Access in routes
101
+ Route::middleware(['auth:sanctum'])->group(function () {
102
+ Route::get('/api/appointments', [AppointmentController::class, 'index']);
103
+ });
104
+
105
+ // Check specific token permissions
106
+ Route::middleware(['auth:sanctum'])->group(function () {
107
+ Route::post('/api/appointments', [AppointmentController::class, 'store'])
108
+ ->middleware('can:create,App\Models\Appointment');
109
+ });
110
+ ```
111
+
112
+ ---
113
+
114
+ ## Profile customization
115
+
116
+ Add fields to the profile update form:
117
+
118
+ ```php
119
+ // app/Actions/Fortify/UpdateUserProfileInformation.php
120
+ public function update(User $user, array $input): void
121
+ {
122
+ Validator::make($input, [
123
+ 'name' => ['required', 'string', 'max:255'],
124
+ 'email' => ['required', 'email', 'unique:users,email,' . $user->id],
125
+ 'phone' => ['nullable', 'string', 'max:20'], // custom field
126
+ ])->validateWithBag('updateProfileInformation');
127
+
128
+ if (isset($input['photo'])) {
129
+ $user->updateProfilePhoto($input['photo']);
130
+ }
131
+
132
+ $user->forceFill([
133
+ 'name' => $input['name'],
134
+ 'email' => $input['email'],
135
+ 'phone' => $input['phone'] ?? null,
136
+ ])->save();
137
+ }
138
+ ```
139
+
140
+ ---
141
+
142
+ ## Two-factor authentication
143
+
144
+ Jetstream includes 2FA via TOTP out of the box.
145
+
146
+ ```php
147
+ // Require 2FA for admin routes
148
+ Route::middleware(['auth', 'verified', '2fa'])->group(function () {
149
+ Route::get('/admin', AdminController::class);
150
+ });
151
+
152
+ // Force users to confirm password before sensitive actions
153
+ Route::middleware(['auth', 'password.confirm'])->group(function () {
154
+ Route::delete('/account', [AccountController::class, 'destroy']);
155
+ });
156
+ ```
157
+
158
+ ---
159
+
160
+ ## Middleware stack understanding
161
+
162
+ ```php
163
+ // web.php — routes available to all
164
+ Route::middleware(['web'])->group(function () { ... });
165
+
166
+ // Authenticated routes
167
+ Route::middleware(['auth', 'verified'])->group(function () { ... });
168
+
169
+ // Team-scoped routes
170
+ Route::middleware(['auth', 'verified', EnsureUserHasTeam::class])->group(function () { ... });
171
+ ```
172
+
173
+ ---
174
+
175
+ ## Custom views — override Jetstream defaults
176
+
177
+ ```bash
178
+ php artisan vendor:publish --tag=jetstream-views
179
+ # Publishes to resources/views/vendor/jetstream/
180
+ ```
181
+
182
+ Override only the views you need. Keep Jetstream's Action classes unless you need custom logic.
183
+
184
+ ---
185
+
186
+ ## Post-install checklist
187
+
188
+ - [ ] Choose Livewire or Inertia (cannot change later)
189
+ - [ ] Decide on Teams before first migration
190
+ - [ ] Configure `FILESYSTEM_DISK` for profile photos (`public` or `s3`)
191
+ - [ ] Set `MAIL_*` env vars — email verification requires working mail
192
+ - [ ] Update `JetstreamServiceProvider` with roles/permissions
193
+ - [ ] Customize `UpdateUserProfileInformation` if adding custom fields
194
+ - [ ] Override views for custom branding
195
+
196
+ ## NEVER
197
+ - Install Jetstream into an existing project without checking for migration conflicts
198
+ - Enable Teams if the domain does not genuinely need multi-tenancy
199
+ - Modify Jetstream Action classes unless customization is explicitly required
200
+ - Mix Jetstream auth with another auth package (Breeze, Fortify standalone) in the same app
@@ -0,0 +1,491 @@
1
+ # Laravel Conventions
2
+
3
+ > Production-grade Laravel. Thin controllers. Explicit intent. No shortcuts.
4
+
5
+ ---
6
+
7
+ ## Project structure
8
+
9
+ ```
10
+ myproject/
11
+ ├── app/
12
+ │ ├── Actions/ # Business logic — one class per operation
13
+ │ ├── Console/
14
+ │ │ └── Commands/
15
+ │ ├── Events/
16
+ │ ├── Exceptions/
17
+ │ ├── Http/
18
+ │ │ ├── Controllers/ # HTTP orchestration only
19
+ │ │ ├── Middleware/
20
+ │ │ └── Requests/ # Form Request classes (validation)
21
+ │ ├── Jobs/
22
+ │ ├── Listeners/
23
+ │ ├── Mail/
24
+ │ ├── Models/ # Eloquent models (singular class name)
25
+ │ ├── Notifications/
26
+ │ ├── Policies/
27
+ │ ├── Providers/
28
+ │ └── View/
29
+ │ └── Components/ # Blade components
30
+ ├── database/
31
+ │ ├── factories/
32
+ │ ├── migrations/
33
+ │ └── seeders/
34
+ ├── resources/
35
+ │ ├── views/
36
+ │ │ ├── users/ # Plural folder per resource
37
+ │ │ │ ├── index.blade.php
38
+ │ │ │ ├── show.blade.php
39
+ │ │ │ ├── create.blade.php
40
+ │ │ │ └── edit.blade.php
41
+ │ │ ├── components/
42
+ │ │ └── layouts/
43
+ │ └── js/
44
+ ├── routes/
45
+ │ ├── web.php
46
+ │ └── api.php
47
+ └── tests/
48
+ ├── Feature/
49
+ └── Unit/
50
+ ```
51
+
52
+ **With Jetstream + Livewire** — additional folders:
53
+ ```
54
+ app/
55
+ └── Livewire/
56
+ ├── Auth/
57
+ └── Users/ # Group components by domain
58
+ ├── UserList.php
59
+ └── EditUser.php
60
+ resources/views/
61
+ └── livewire/
62
+ ├── auth/
63
+ └── users/
64
+ ├── user-list.blade.php # kebab-case filename matches component
65
+ └── edit-user.blade.php
66
+ ```
67
+
68
+ ---
69
+
70
+ ## Naming conventions
71
+
72
+ | Artifact | Convention | Example |
73
+ |---|---|---|
74
+ | Model | Singular, PascalCase | `User`, `BlogPost` |
75
+ | Table | Plural, snake_case | `users`, `blog_posts` |
76
+ | Controller | Singular model + `Controller` | `UserController`, `BlogPostController` |
77
+ | Form Request | Action + model | `CreateUserRequest`, `UpdateUserRequest` |
78
+ | Action | Verb + noun + `Action` | `CreateUserAction`, `SendWelcomeEmailAction` |
79
+ | Policy | Singular model + `Policy` | `UserPolicy` |
80
+ | Event | Past-tense noun phrase | `UserCreated`, `OrderShipped` |
81
+ | Listener | Present verb phrase | `SendWelcomeEmail`, `NotifyAdminOfOrder` |
82
+ | Job | Imperative verb phrase | `GenerateInvoice`, `ProcessPayment` |
83
+ | API Resource | Singular model + `Resource` | `UserResource` |
84
+ | Livewire component class | PascalCase, singular or descriptive | `UserList`, `EditUser` |
85
+ | Livewire component file | kebab-case matching class | `user-list.blade.php` |
86
+ | View folder | Plural, kebab-case | `users/`, `blog-posts/` |
87
+ | Route URI | Plural, kebab-case | `/users`, `/blog-posts` |
88
+ | Migration | `create_table_table`, `add_col_to_table` | `create_users_table` |
89
+
90
+ **Singular vs plural rule of thumb:**
91
+ - Class names → **singular** (represents one record: `User`, `Order`)
92
+ - Folders grouping multiple files → **plural** (`Controllers/`, `Models/`, `views/users/`)
93
+ - Database tables and route URIs → **plural** (`users`, `/orders`)
94
+
95
+ ---
96
+
97
+ ## Controllers — HTTP orchestration only
98
+
99
+ Controllers validate the request, call an Action, and return a response. Nothing else.
100
+
101
+ ```php
102
+ // WRONG — business logic in controller
103
+ public function store(Request $request)
104
+ {
105
+ if (Appointment::where('doctor_id', $request->doctor_id)
106
+ ->whereDate('date', $request->date)->exists()) {
107
+ return back()->withErrors(['date' => 'Already booked.']);
108
+ }
109
+ $appointment = Appointment::create([...]);
110
+ Mail::to(auth()->user())->send(new AppointmentConfirmed($appointment));
111
+ return redirect()->route('appointments.index');
112
+ }
113
+
114
+ // RIGHT — controller as orchestrator
115
+ public function store(CreateAppointmentRequest $request): RedirectResponse
116
+ {
117
+ $appointment = (new CreateAppointmentAction)->execute(
118
+ auth()->user(),
119
+ AppointmentData::fromRequest($request)
120
+ );
121
+ return redirect()->route('appointments.show', $appointment);
122
+ }
123
+ ```
124
+
125
+ ---
126
+
127
+ ## Form Requests — all validation lives here
128
+
129
+ ```php
130
+ class CreateAppointmentRequest extends FormRequest
131
+ {
132
+ public function authorize(): bool
133
+ {
134
+ return $this->user()->can('create', Appointment::class);
135
+ }
136
+
137
+ public function rules(): array
138
+ {
139
+ return [
140
+ 'doctor_id' => ['required', 'exists:doctors,id'],
141
+ 'date' => ['required', 'date', 'after:today'],
142
+ 'notes' => ['nullable', 'string', 'max:500'],
143
+ ];
144
+ }
145
+
146
+ public function messages(): array
147
+ {
148
+ return [
149
+ 'date.after' => 'The appointment must be scheduled for a future date.',
150
+ ];
151
+ }
152
+ }
153
+ ```
154
+
155
+ ---
156
+
157
+ ## Actions — one class, one business operation
158
+
159
+ ```php
160
+ // app/Actions/CreateAppointmentAction.php
161
+ class CreateAppointmentAction
162
+ {
163
+ public function execute(User $user, AppointmentData $data): Appointment
164
+ {
165
+ $this->ensureNoConflict($data->doctorId, $data->date);
166
+
167
+ $appointment = Appointment::create([
168
+ 'user_id' => $user->id,
169
+ 'doctor_id' => $data->doctorId,
170
+ 'date' => $data->date,
171
+ 'notes' => $data->notes,
172
+ ]);
173
+
174
+ AppointmentCreated::dispatch($appointment);
175
+
176
+ return $appointment;
177
+ }
178
+
179
+ private function ensureNoConflict(int $doctorId, Carbon $date): void
180
+ {
181
+ if (Appointment::where('doctor_id', $doctorId)
182
+ ->whereDate('date', $date)
183
+ ->where('status', '!=', 'cancelled')
184
+ ->exists()) {
185
+ throw new AppointmentConflictException();
186
+ }
187
+ }
188
+ }
189
+ ```
190
+
191
+ ---
192
+
193
+ ## Policies — authorization layer, not inside Actions
194
+
195
+ ```php
196
+ class AppointmentPolicy
197
+ {
198
+ public function view(User $user, Appointment $appointment): bool
199
+ {
200
+ return $user->id === $appointment->user_id
201
+ || $user->hasRole('admin');
202
+ }
203
+
204
+ public function cancel(User $user, Appointment $appointment): bool
205
+ {
206
+ return $this->view($user, $appointment)
207
+ && $appointment->date->isAfter(now()->addHours(24));
208
+ }
209
+ }
210
+ ```
211
+
212
+ Call via `$this->authorize('cancel', $appointment)` in controllers or Form Requests.
213
+
214
+ ---
215
+
216
+ ## Events + Listeners — side effects always async/queued
217
+
218
+ Never call external services synchronously inside an Action.
219
+
220
+ ```php
221
+ // Event — carries minimum required data
222
+ class AppointmentCreated
223
+ {
224
+ use Dispatchable, SerializesModels;
225
+ public function __construct(public readonly Appointment $appointment) {}
226
+ }
227
+
228
+ // Listener — always queued
229
+ class SendConfirmationEmail implements ShouldQueue
230
+ {
231
+ public int $tries = 3;
232
+
233
+ public function handle(AppointmentCreated $event): void
234
+ {
235
+ Mail::to($event->appointment->user)
236
+ ->send(new AppointmentConfirmedMail($event->appointment));
237
+ }
238
+ }
239
+ ```
240
+
241
+ ---
242
+
243
+ ## Jobs — long-running or retriable work
244
+
245
+ ```php
246
+ class GenerateInvoiceJob implements ShouldQueue
247
+ {
248
+ use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
249
+
250
+ public int $tries = 3;
251
+ public int $backoff = 60;
252
+
253
+ public function __construct(private readonly Order $order) {}
254
+
255
+ public function handle(InvoiceService $service): void
256
+ {
257
+ $service->generate($this->order);
258
+ }
259
+
260
+ public function failed(Throwable $e): void
261
+ {
262
+ Log::error('Invoice generation failed', [
263
+ 'order_id' => $this->order->id,
264
+ 'error' => $e->getMessage(),
265
+ ]);
266
+ }
267
+ }
268
+ ```
269
+
270
+ ---
271
+
272
+ ## API Resources — always transform, never expose raw models
273
+
274
+ ```php
275
+ class AppointmentResource extends JsonResource
276
+ {
277
+ public function toArray(Request $request): array
278
+ {
279
+ return [
280
+ 'id' => $this->id,
281
+ 'date' => $this->date->toIso8601String(),
282
+ 'status' => $this->status,
283
+ 'doctor' => new DoctorResource($this->whenLoaded('doctor')),
284
+ 'can' => [
285
+ 'cancel' => $request->user()->can('cancel', $this->resource),
286
+ ],
287
+ ];
288
+ }
289
+ }
290
+ ```
291
+
292
+ ---
293
+
294
+ ## N+1 prevention
295
+
296
+ ```php
297
+ // WRONG — N+1 (one query per row)
298
+ $appointments = Appointment::all();
299
+ foreach ($appointments as $a) { echo $a->doctor->name; }
300
+
301
+ // RIGHT — eager loading
302
+ $appointments = Appointment::with(['doctor.user', 'patient'])->paginate(20);
303
+
304
+ // Define reusable scope on the model
305
+ public function scopeWithRelations(Builder $query): Builder
306
+ {
307
+ return $query->with(['doctor.user', 'patient']);
308
+ }
309
+ ```
310
+
311
+ Use Laravel Debugbar or Telescope in dev to catch N+1 before production.
312
+
313
+ ---
314
+
315
+ ## Model conventions
316
+
317
+ ```php
318
+ class Appointment extends Model
319
+ {
320
+ protected $fillable = ['user_id', 'doctor_id', 'date', 'status', 'notes'];
321
+
322
+ protected $casts = [
323
+ 'date' => 'datetime',
324
+ 'cancelled_at' => 'datetime',
325
+ ];
326
+
327
+ public function scopePending(Builder $query): Builder
328
+ {
329
+ return $query->where('status', 'pending');
330
+ }
331
+
332
+ public function scopeUpcoming(Builder $query): Builder
333
+ {
334
+ return $query->where('date', '>', now())->orderBy('date');
335
+ }
336
+
337
+ public function doctor(): BelongsTo
338
+ {
339
+ return $this->belongsTo(Doctor::class);
340
+ }
341
+ }
342
+ ```
343
+
344
+ ---
345
+
346
+ ## Migrations
347
+
348
+ - One migration per schema change — never edit after deployment.
349
+ - Always add foreign key constraints.
350
+ - Name columns after the domain: `cancelled_at`, not `is_cancelled_timestamp`.
351
+ - Add indexes for columns used in WHERE clauses and ORDER BY.
352
+
353
+ ```php
354
+ Schema::create('appointments', function (Blueprint $table) {
355
+ $table->id();
356
+ $table->foreignId('user_id')->constrained()->cascadeOnDelete();
357
+ $table->foreignId('doctor_id')->constrained()->restrictOnDelete();
358
+ $table->dateTime('date');
359
+ $table->enum('status', ['pending', 'confirmed', 'cancelled'])->default('pending');
360
+ $table->text('notes')->nullable();
361
+ $table->timestamp('cancelled_at')->nullable();
362
+ $table->timestamps();
363
+
364
+ $table->index(['doctor_id', 'date']); // for conflict checks
365
+ });
366
+ ```
367
+
368
+ ---
369
+
370
+ ## Testing
371
+
372
+ ```php
373
+ // Feature — test full HTTP layer
374
+ test('patient can book appointment', function () {
375
+ $patient = User::factory()->create();
376
+ $doctor = Doctor::factory()->create();
377
+
378
+ actingAs($patient)
379
+ ->post(route('appointments.store'), [
380
+ 'doctor_id' => $doctor->id,
381
+ 'date' => now()->addDay()->toDateTimeString(),
382
+ ])
383
+ ->assertRedirect();
384
+
385
+ expect(Appointment::where('user_id', $patient->id)->exists())->toBeTrue();
386
+ });
387
+
388
+ // Unit — test Actions in isolation
389
+ test('CreateAppointmentAction throws on conflict', function () {
390
+ $existing = Appointment::factory()->confirmed()->create();
391
+
392
+ expect(fn () => (new CreateAppointmentAction)->execute(
393
+ $existing->user,
394
+ AppointmentData::from(['doctor_id' => $existing->doctor_id, 'date' => $existing->date])
395
+ ))->toThrow(AppointmentConflictException::class);
396
+ });
397
+ ```
398
+
399
+ ---
400
+
401
+ ## Livewire components (Jetstream stack)
402
+
403
+ Livewire replaces full-page controllers for interactive UI. Use it instead of writing separate Vue/React components when the project is on the Jetstream+Livewire stack.
404
+
405
+ ```php
406
+ // app/Livewire/Users/UserList.php
407
+ namespace App\Livewire\Users;
408
+
409
+ use Livewire\Component;
410
+ use Livewire\WithPagination;
411
+ use Livewire\Attributes\Computed;
412
+
413
+ class UserList extends Component
414
+ {
415
+ use WithPagination;
416
+
417
+ public string $search = '';
418
+
419
+ // Computed property — recalculates automatically when $search changes
420
+ #[Computed]
421
+ public function users(): \Illuminate\Contracts\Pagination\LengthAwarePaginator
422
+ {
423
+ return User::query()
424
+ ->when($this->search, fn ($q) => $q->where('name', 'like', "%{$this->search}%"))
425
+ ->paginate(10);
426
+ }
427
+
428
+ public function render(): \Illuminate\View\View
429
+ {
430
+ return view('livewire.users.user-list');
431
+ }
432
+ }
433
+ ```
434
+
435
+ ```blade
436
+ {{-- resources/views/livewire/users/user-list.blade.php --}}
437
+ <div>
438
+ <input wire:model.live="search" type="text" placeholder="Search…" />
439
+
440
+ @foreach ($this->users as $user)
441
+ <div>{{ $user->name }}</div>
442
+ @endforeach
443
+
444
+ {{ $this->users->links() }}
445
+ </div>
446
+ ```
447
+
448
+ **Livewire conventions:**
449
+ - Class in `app/Livewire/<Domain>/ClassName.php` (PascalCase)
450
+ - View in `resources/views/livewire/<domain>/class-name.blade.php` (kebab-case)
451
+ - Use `#[Computed]` for derived data — never store computed values in public properties
452
+ - Use `wire:model.live` for real-time search; `wire:model.lazy` for form inputs (debounce on blur)
453
+ - Keep business logic in Actions — Livewire component only wires input → Action → response
454
+ - Never query DB inside Blade template — use `#[Computed]` property
455
+
456
+ **Classic controller variant (same project, non-Livewire views):**
457
+ ```php
458
+ // app/Http/Controllers/UserController.php
459
+ class UserController extends Controller
460
+ {
461
+ public function index(Request $request): View
462
+ {
463
+ $users = User::query()
464
+ ->when($request->search, fn ($q) => $q->where('name', 'like', "%{$request->search}%"))
465
+ ->paginate(10);
466
+
467
+ return view('users.index', compact('users'));
468
+ }
469
+ }
470
+ ```
471
+
472
+ Both patterns coexist fine in a Jetstream project — Livewire for interactive pages, classic controllers for simple read-only or API routes.
473
+
474
+ ---
475
+
476
+ ## ALWAYS
477
+ - Form Requests for validation
478
+ - Actions for business logic
479
+ - Policies for authorization
480
+ - Events + queued Listeners for side effects
481
+ - API Resources for JSON responses
482
+ - Eager loading with `with()`
483
+ - Follow naming conventions: singular classes, plural tables and view folders
484
+
485
+ ## NEVER
486
+ - Business logic in controllers
487
+ - `Mail::send()` synchronously in request cycle
488
+ - `Auth::user()` inside an Action (inject `User` instead)
489
+ - Raw `DB::table()` queries bypassing Eloquent in feature code
490
+ - Exposing Eloquent models directly in API responses
491
+ - Queries inside Blade or Livewire templates directly (use `#[Computed]` or pass via controller)