Skip to content

fix: resolve Prisma alunoId for ALUNO role to avoid FK violation#174

Merged
EmiyaKiritsugu3 merged 4 commits into
mainfrom
fix/aluno-fk-resolve
Jul 5, 2026
Merged

fix: resolve Prisma alunoId for ALUNO role to avoid FK violation#174
EmiyaKiritsugu3 merged 4 commits into
mainfrom
fix/aluno-fk-resolve

Conversation

@EmiyaKiritsugu3

@EmiyaKiritsugu3 EmiyaKiritsugu3 commented Jul 5, 2026

Copy link
Copy Markdown
Owner

Problema

FK violation treinos_alunoId_fkey ao salvar treino gerado por IA.

Causa

performTreinoUpsert usava user.id (Auth UUID) como alunoId p/ ALUNO.
Registro aluno no Prisma pode ter UUID diferente do Auth.

Fix

Nova resolveAlunoId() busca aluno.id no Prisma pelo email antes do create.
Aplicada em performTreinoUpsert e batchUpsertTreinoAction.

Verificação

  • npm run typecheck: 0 errors
  • npm run test: all pass

Summary by cubic

Fixes FK violations when ALUNO users save treinos by resolving the correct Prisma alunoId from email. Also unblocks CI by suppressing a false-positive lint, aligning middleware.ts formatting with prettier 3.9.4, and excluding docs/superpowers/ from Prettier checks.

  • Bug Fixes
    • Resolve Prisma aluno.id by email for ALUNO role and use it in single and batch upserts; prevents treinos_alunoId_fkey errors.
    • Unblock CI: suppress react-hooks/incompatible-library false positive for TanStack useReactTable and reformat middleware.ts union type to match prettier 3.9.4.
    • Exclude docs/superpowers/ from prettier to prevent format gate failures on auto-generated files.

Written for commit 004e4af. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • Bug Fixes
    • Fixed treino saving/upserting for standard users so treino records are linked to the correct aluno identity (matching the authenticated account).
    • Improved batch treino validation and creation to consistently resolve and preserve the correct association for each item.
    • Reduced cases where treino entries could be attached to the wrong identity during save or validation.

getAuthRole() returns role=null for ALUNO (no funcionarios record).
Previous code used auth user.id as alunoId, but Prisma aluno.id
may differ from Supabase Auth UUID. Added resolveAlunoId() helper
that looks up the correct aluno.id by email before create.

Fixes: foreign key constraint violation on treinos_alunoId_fkey
when ALUNO saves AI-generated workout.
@vercel

vercel Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
smartmanagementsystem Ready Ready Preview, Comment Jul 5, 2026 1:02pm

@coderabbitai

coderabbitai Bot commented Jul 5, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Modifies src/lib/actions/treinos.ts to resolve treino alunoId through Prisma before upsert, using the authenticated user’s email with a fallback to user.id. Adds a hook lint suppression comment in src/components/dashboard/alunos/data-table.tsx.

Changes

Aluno ID Resolution Fix

Layer / File(s) Summary
resolveAlunoId helper and single treino upsert
src/lib/actions/treinos.ts
Adds resolveAlunoId(user) to look up Prisma aluno.id by email (fallback to user.id), and performTreinoUpsert now uses this resolved value for role === null instead of user.id.
Batch upsert alunoId resolution
src/lib/actions/treinos.ts
batchUpsertTreinoAction resolves alunoId per treino during validation via resolveAlunoId, replacing the prior in-transaction conditional alunoId: role === null ? user.id : ... with the pre-resolved data.alunoId.

React table lint suppression

Layer / File(s) Summary
useReactTable suppression comment
src/components/dashboard/alunos/data-table.tsx
Adds comments and an eslint-disable-next-line react-hooks/incompatible-library directive immediately before useReactTable.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description explains the bug, cause, fix, and verification, but it omits required template sections like Type of Change, Related Documents, and Checklist. Add the missing template sections: Type of Change, Related Documents, and Checklist, and fill in any applicable links or validation results.
✅ Passed checks (4 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title accurately summarizes the main change: resolving Prisma alunoId for ALUNO treinos to prevent FK violations.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/aluno-fk-resolve

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/lib/actions/treinos.ts (1)

185-190: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Resolve alunoId once instead of per-treino; drop the redundant spread override.

For role === null, resolveAlunoId(user) returns the same value for every treino in the batch, yet it runs one DB query per treino inside Promise.all (N redundant lookups). Also { ...t, alunoId: t.alunoId } is a no-op since alunoId is already in t. Resolve once before mapping.

♻️ Suggested refactor
-        const validated = await Promise.all(
-          treinos.map(async (t) => ({
-            ...TreinoBaseSchema.parse({ ...t, alunoId: t.alunoId }),
-            alunoId: role === null ? await resolveAlunoId(user) : t.alunoId,
-          }))
-        );
+        const resolvedAlunoId = role === null ? await resolveAlunoId(user) : null;
+        const validated = treinos.map((t) => {
+          const parsed = TreinoBaseSchema.parse(t);
+          return { ...parsed, alunoId: resolvedAlunoId ?? t.alunoId };
+        });
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/actions/treinos.ts` around lines 185 - 190, Resolve `alunoId` once
before the `Promise.all` map in `treinos.ts` instead of calling
`resolveAlunoId(user)` for every item when `role === null`, and reuse that
single value for each treino in the batch. Also remove the redundant `{ ...t,
alunoId: t.alunoId }` spread/override in the `TreinoBaseSchema.parse` call,
since `alunoId` already comes from `t`. Keep the change localized around the
validation mapping logic in the `validated` निर्माण.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/lib/actions/treinos.ts`:
- Around line 52-53: `resolveAlunoId` is still falling back to `user.id` for
ALUNO, which can reintroduce the `treinos_alunoId_fkey` violation; update this
helper to fail explicitly when the `prisma.aluno.findUnique` lookup does not
return a match for `role === null`. Also stop using `user.email ?? ''` in the
lookup, and handle a missing email as an error or invalid state rather than
querying with an empty string. Keep the fix centered in `resolveAlunoId` so the
caller only proceeds with a real `aluno.id`.
- Line 63: The ownership check in the treino flow is still comparing
existingTreino.alunoId against user.id, which can reject valid ALUNO owners when
their aluno id is different from the Supabase user id. Update the check in the
relevant treino action to compare against the resolved alunoId variable instead,
matching the create and batch paths, and use the existing
resolveAlunoId/validatedData.alunoId logic to keep ownership consistent.

---

Nitpick comments:
In `@src/lib/actions/treinos.ts`:
- Around line 185-190: Resolve `alunoId` once before the `Promise.all` map in
`treinos.ts` instead of calling `resolveAlunoId(user)` for every item when `role
=== null`, and reuse that single value for each treino in the batch. Also remove
the redundant `{ ...t, alunoId: t.alunoId }` spread/override in the
`TreinoBaseSchema.parse` call, since `alunoId` already comes from `t`. Keep the
change localized around the validation mapping logic in the `validated` निर्माण.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 13785a08-52b8-416f-ac32-aed44d5d88ab

📥 Commits

Reviewing files that changed from the base of the PR and between 26cc77a and feef161.

📒 Files selected for processing (1)
  • src/lib/actions/treinos.ts

Comment on lines +52 to +53
const aluno = await prisma.aluno.findUnique({ where: { email: user.email ?? '' } });
return aluno?.id ?? user.id;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Silent fallback reintroduces the FK violation this PR fixes.

For role === null (ALUNO), if the email lookup misses, resolveAlunoId returns user.id — the exact Supabase Auth UUID that causes treinos_alunoId_fkey to fail. Additionally, user.email ?? '' turns a missing email into a lookup for an aluno with an empty-string email, which can match the wrong record or silently miss. Consider failing explicitly for ALUNO when no matching aluno is found rather than falling back.

🛠️ Suggested handling
-async function resolveAlunoId(user: { id: string; email?: string | null }): Promise<string> {
-  const aluno = await prisma.aluno.findUnique({ where: { email: user.email ?? '' } });
-  return aluno?.id ?? user.id;
-}
+async function resolveAlunoId(user: { id: string; email?: string | null }): Promise<string> {
+  if (!user.email) throw new Error('E-mail do usuário não disponível para resolver o aluno.');
+  const aluno = await prisma.aluno.findUnique({ where: { email: user.email } });
+  if (!aluno) throw new Error('Aluno correspondente não encontrado.');
+  return aluno.id;
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const aluno = await prisma.aluno.findUnique({ where: { email: user.email ?? '' } });
return aluno?.id ?? user.id;
if (!user.email) throw new Error('E-mail do usuário não disponível para resolver o aluno.');
const aluno = await prisma.aluno.findUnique({ where: { email: user.email } });
if (!aluno) throw new Error('Aluno correspondente não encontrado.');
return aluno.id;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/actions/treinos.ts` around lines 52 - 53, `resolveAlunoId` is still
falling back to `user.id` for ALUNO, which can reintroduce the
`treinos_alunoId_fkey` violation; update this helper to fail explicitly when the
`prisma.aluno.findUnique` lookup does not return a match for `role === null`.
Also stop using `user.email ?? ''` in the lookup, and handle a missing email as
an error or invalid state rather than querying with an empty string. Keep the
fix centered in `resolveAlunoId` so the caller only proceeds with a real
`aluno.id`.

) {
const { objetivo, exercicios, diaSemana } = validatedData;
const alunoId = role === null ? user.id : validatedData.alunoId;
const alunoId = role === null ? await resolveAlunoId(user) : validatedData.alunoId;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

sed -n '1,180p' src/lib/actions/treinos.ts

Repository: EmiyaKiritsugu3/PWeb_Project

Length of output: 6322


🏁 Script executed:

rg -n "resolveAlunoId|existingTreino\.alunoId === user\.id|aluno\.id may differ|alunoId === user\.id" src/lib/actions src/lib utils

Repository: EmiyaKiritsugu3/PWeb_Project

Length of output: 1052


Use the resolved alunoId in the ownership check

existingTreino.alunoId === user.id will block ALUNO owners when aluno.id differs from the Supabase user id. Compare against the resolved alunoId here, matching the create/batch paths.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/lib/actions/treinos.ts` at line 63, The ownership check in the treino
flow is still comparing existingTreino.alunoId against user.id, which can reject
valid ALUNO owners when their aluno id is different from the Supabase user id.
Update the check in the relevant treino action to compare against the resolved
alunoId variable instead, matching the create and batch paths, and use the
existing resolveAlunoId/validatedData.alunoId logic to keep ownership
consistent.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4 issues found across 1 file

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/lib/actions/treinos.ts">

<violation number="1" location="src/lib/actions/treinos.ts:51">
P2: Custom agent: **Enforce Pragmatic Test Coverage**

New `resolveAlunoId` logic is core business logic with two distinct paths (aluno found by email / fallback to auth id), but neither path is tested. The existing `treinos.test.ts` covers `upsertTreinoAction` and `batchUpsertTreinoAction` for INSTRUTOR, GERENTE, and RECEPCIONISTA roles, yet there are no test cases for the ALUNO role (`role === null`) that would exercise `resolveAlunoId`. This leaves the success and fallback paths uncovered.</violation>

<violation number="2" location="src/lib/actions/treinos.ts:52">
P1: Custom agent: **Enforce Strict Maintainability Standards**

The `resolveAlunoId` helper silently falls back to `user.id` when no Prisma `aluno` record is found by email. Because the PR itself notes that `aluno.id` may differ from the Auth `user.id`, this fallback can still cause the FK violation the PR is fixing and masks a data-integrity issue. The same file already handles a missing aluno explicitly in `registrarHistoricoTreinoAction` (line 356) by throwing an error; `resolveAlunoId` should follow that pattern instead of using a silent fallback.</violation>

<violation number="3" location="src/lib/actions/treinos.ts:63">
P0: ALUNO users will be unable to edit their own treinos after this change. The authorization check `existingTreino.alunoId === user.id` at line 75 compares the stored Prisma `alunoId` against the auth `user.id`. Before this fix, both were the same (auth user ID). Now the CREATE flow stores the resolved Prisma aluno ID, but the UPDATE authorization check still uses `user.id`. When a student creates a treino and later tries to edit it, the stored `alunoId` is the Prisma ID, which differs from the auth `user.id`, so the check fails returning "Acesso não autorizado para edição". The fix should also check against the resolved `alunoId`, e.g., `existingTreino.alunoId === user.id || existingTreino.alunoId === alunoId`.</violation>

<violation number="4" location="src/lib/actions/treinos.ts:186">
P2: In the batch upsert flow, `resolveAlunoId(user)` is called once per treino inside a `Promise.all(treinos.map(...))`, but the result is always the same for the same user. This generates N identical `prisma.aluno.findUnique` queries instead of one. For a batch of 10 treinos, that's 9 unnecessary database round-trips in parallel. Consider hoisting the call before the loop: `const resolvedAlunoId = role === null ? await resolveAlunoId(user) : undefined;` then reference `resolvedAlunoId` inside the map.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

) {
const { objetivo, exercicios, diaSemana } = validatedData;
const alunoId = role === null ? user.id : validatedData.alunoId;
const alunoId = role === null ? await resolveAlunoId(user) : validatedData.alunoId;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P0: ALUNO users will be unable to edit their own treinos after this change. The authorization check existingTreino.alunoId === user.id at line 75 compares the stored Prisma alunoId against the auth user.id. Before this fix, both were the same (auth user ID). Now the CREATE flow stores the resolved Prisma aluno ID, but the UPDATE authorization check still uses user.id. When a student creates a treino and later tries to edit it, the stored alunoId is the Prisma ID, which differs from the auth user.id, so the check fails returning "Acesso não autorizado para edição". The fix should also check against the resolved alunoId, e.g., existingTreino.alunoId === user.id || existingTreino.alunoId === alunoId.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/lib/actions/treinos.ts, line 63:

<comment>ALUNO users will be unable to edit their own treinos after this change. The authorization check `existingTreino.alunoId === user.id` at line 75 compares the stored Prisma `alunoId` against the auth `user.id`. Before this fix, both were the same (auth user ID). Now the CREATE flow stores the resolved Prisma aluno ID, but the UPDATE authorization check still uses `user.id`. When a student creates a treino and later tries to edit it, the stored `alunoId` is the Prisma ID, which differs from the auth `user.id`, so the check fails returning "Acesso não autorizado para edição". The fix should also check against the resolved `alunoId`, e.g., `existingTreino.alunoId === user.id || existingTreino.alunoId === alunoId`.</comment>

<file context>
@@ -43,14 +43,24 @@ async function getAuthRole() {
 ) {
   const { objetivo, exercicios, diaSemana } = validatedData;
-  const alunoId = role === null ? user.id : validatedData.alunoId;
+  const alunoId = role === null ? await resolveAlunoId(user) : validatedData.alunoId;
   const id = 'id' in validatedData ? (validatedData as TreinoBase & { id: string }).id : undefined;
 
</file context>

* Resolve the correct alunoId from Prisma by email to avoid FK violation.
*/
async function resolveAlunoId(user: { id: string; email?: string | null }): Promise<string> {
const aluno = await prisma.aluno.findUnique({ where: { email: user.email ?? '' } });

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Custom agent: Enforce Strict Maintainability Standards

The resolveAlunoId helper silently falls back to user.id when no Prisma aluno record is found by email. Because the PR itself notes that aluno.id may differ from the Auth user.id, this fallback can still cause the FK violation the PR is fixing and masks a data-integrity issue. The same file already handles a missing aluno explicitly in registrarHistoricoTreinoAction (line 356) by throwing an error; resolveAlunoId should follow that pattern instead of using a silent fallback.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/lib/actions/treinos.ts, line 52:

<comment>The `resolveAlunoId` helper silently falls back to `user.id` when no Prisma `aluno` record is found by email. Because the PR itself notes that `aluno.id` may differ from the Auth `user.id`, this fallback can still cause the FK violation the PR is fixing and masks a data-integrity issue. The same file already handles a missing aluno explicitly in `registrarHistoricoTreinoAction` (line 356) by throwing an error; `resolveAlunoId` should follow that pattern instead of using a silent fallback.</comment>

<file context>
@@ -43,14 +43,24 @@ async function getAuthRole() {
+ * Resolve the correct alunoId from Prisma by email to avoid FK violation.
+ */
+async function resolveAlunoId(user: { id: string; email?: string | null }): Promise<string> {
+  const aluno = await prisma.aluno.findUnique({ where: { email: user.email ?? '' } });
+  return aluno?.id ?? user.id;
+}
</file context>

* Their Prisma `aluno.id` may differ from Supabase Auth `user.id`.
* Resolve the correct alunoId from Prisma by email to avoid FK violation.
*/
async function resolveAlunoId(user: { id: string; email?: string | null }): Promise<string> {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Custom agent: Enforce Pragmatic Test Coverage

New resolveAlunoId logic is core business logic with two distinct paths (aluno found by email / fallback to auth id), but neither path is tested. The existing treinos.test.ts covers upsertTreinoAction and batchUpsertTreinoAction for INSTRUTOR, GERENTE, and RECEPCIONISTA roles, yet there are no test cases for the ALUNO role (role === null) that would exercise resolveAlunoId. This leaves the success and fallback paths uncovered.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/lib/actions/treinos.ts, line 51:

<comment>New `resolveAlunoId` logic is core business logic with two distinct paths (aluno found by email / fallback to auth id), but neither path is tested. The existing `treinos.test.ts` covers `upsertTreinoAction` and `batchUpsertTreinoAction` for INSTRUTOR, GERENTE, and RECEPCIONISTA roles, yet there are no test cases for the ALUNO role (`role === null`) that would exercise `resolveAlunoId`. This leaves the success and fallback paths uncovered.</comment>

<file context>
@@ -43,14 +43,24 @@ async function getAuthRole() {
+ * Their Prisma `aluno.id` may differ from Supabase Auth `user.id`.
+ * Resolve the correct alunoId from Prisma by email to avoid FK violation.
+ */
+async function resolveAlunoId(user: { id: string; email?: string | null }): Promise<string> {
+  const aluno = await prisma.aluno.findUnique({ where: { email: user.email ?? '' } });
+  return aluno?.id ?? user.id;
</file context>


const validated = treinos.map((t) => TreinoBaseSchema.parse({ ...t, alunoId: t.alunoId }));
const validated = await Promise.all(
treinos.map(async (t) => ({

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: In the batch upsert flow, resolveAlunoId(user) is called once per treino inside a Promise.all(treinos.map(...)), but the result is always the same for the same user. This generates N identical prisma.aluno.findUnique queries instead of one. For a batch of 10 treinos, that's 9 unnecessary database round-trips in parallel. Consider hoisting the call before the loop: const resolvedAlunoId = role === null ? await resolveAlunoId(user) : undefined; then reference resolvedAlunoId inside the map.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/lib/actions/treinos.ts, line 186:

<comment>In the batch upsert flow, `resolveAlunoId(user)` is called once per treino inside a `Promise.all(treinos.map(...))`, but the result is always the same for the same user. This generates N identical `prisma.aluno.findUnique` queries instead of one. For a batch of 10 treinos, that's 9 unnecessary database round-trips in parallel. Consider hoisting the call before the loop: `const resolvedAlunoId = role === null ? await resolveAlunoId(user) : undefined;` then reference `resolvedAlunoId` inside the map.</comment>

<file context>
@@ -172,15 +182,20 @@ export async function batchUpsertTreinoAction(
 
-        const validated = treinos.map((t) => TreinoBaseSchema.parse({ ...t, alunoId: t.alunoId }));
+        const validated = await Promise.all(
+          treinos.map(async (t) => ({
+            ...TreinoBaseSchema.parse({ ...t, alunoId: t.alunoId }),
+            alunoId: role === null ? await resolveAlunoId(user) : t.alunoId,
</file context>

…n TanStack Table useReactTable

CI Quality Gates failing on data-table.tsx:46 — react-hooks/incompatible-library
warning treated as failure. TanStack Table useReactTable returns non-memoizable
fns by design; React Compiler rule is a false positive. Suppression unblocks
PR #174 + main CI.

Co-Authored-By: Claude <noreply@anthropic.com>
…ier 3.9.4

data-table.tsx: eslint-disable useReactTable incompatible-library
rule (TanStack fns non-memoizable by design, false positive).

middleware.ts: prettier 3.9.4 reformats union type (local 3.8.3
stale vs CI 3.9.4).

Unblocks PR #174 Quality Gates and broken main CI.

Co-Authored-By: Claude <noreply@anthropic.com>
Auto-generated plan files not source code. Broke CI format gate
on main + PR #174.

Co-Authored-By: Claude <noreply@anthropic.com>
@EmiyaKiritsugu3 EmiyaKiritsugu3 merged commit 8fba34b into main Jul 5, 2026
12 checks passed
@EmiyaKiritsugu3 EmiyaKiritsugu3 deleted the fix/aluno-fk-resolve branch July 5, 2026 13:02
@sonarqubecloud

sonarqubecloud Bot commented Jul 5, 2026

Copy link
Copy Markdown

EmiyaKiritsugu3 added a commit that referenced this pull request Jul 5, 2026
…rization

deleteTreinoAction and updateTreinoDayAction compared treino.alunoId
(Prisma ID) against user.id (Auth UUID), always mismatching after
PR #174 FK fix. Resolve aluno.id by email before auth check.

Co-Authored-By: Claude <noreply@anthropic.com>
EmiyaKiritsugu3 added a commit that referenced this pull request Jul 5, 2026
…nos (#175)

* docs: meus treinos UX improvements design spec

Co-Authored-By: Claude <noreply@anthropic.com>

* docs: detailed implementation plan for meus treinos UX improvements

Co-Authored-By: Claude <noreply@anthropic.com>

* feat(workout-editor): add compact prop to drop outer Card wrapper

- Add compact?: boolean prop (default false) to WorkoutEditor
- Extract JSX into const content, conditionally wrap in div vs Card
- Add 2 tests: compact omits Card, default renders Card

Co-Authored-By: Claude <noreply@anthropic.com>

* feat(ux): expose planName from useWorkoutGeneration for visual grouper banner

* feat(ux): inline editor inside treino cards, remove bottom editor

- editingTreinoId state drives inline WorkoutEditor per card
- handleEditLocal replaces scrollTo behavior
- Criar Manual button moved above list, opens inline editor
- Removed bottom-of-page conditional editor
- Removed window.scrollTo from use-workout-crud

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(test): update use-workout-crud tests for inline editor changes

Co-Authored-By: Claude <noreply@anthropic.com>

* feat(ux): visual grouper banner + after-gen scroll anchor

Co-Authored-By: Claude <noreply@anthropic.com>

* test(ux): update meus-treinos-client tests for planName banner

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(ux): reset planName before each generation

Ensures banner re-triggers on every AI gen, not just first time.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(ux): add plan description to banner card

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(ux): retry scroll with requestAnimationFrame until DOM ready

Replaces fixed 300ms setTimeout with rAF loop that retries
until #treinos-pessoais anchor exists in DOM. Eliminates
race condition on slow devices / slow RSC renders.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(auth): resolve Prisma alunoId vs Auth UUID in delete+update authorization

deleteTreinoAction and updateTreinoDayAction compared treino.alunoId
(Prisma ID) against user.id (Auth UUID), always mismatching after
PR #174 FK fix. Resolve aluno.id by email before auth check.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(review): address PR #175 review findings — all severity levels

- rAF scroll capped at 20 attempts (prevents infinite loop)
- handleDelete + handleDayChange: surface server errors to user
- replace inline prisma.aluno.findUnique with resolveAlunoId() for auth
- add onSuccess to useCallback dep array

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(type): make onSuccess optional in useWorkoutGeneration

Pre-existing tests don't pass onSuccess — made optional to avoid
12 TS2345 errors. Caller (meus-treinos-client) always passes it.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(ux): keep editor open on save failure + dead code cleanup

handleSave returns boolean. Client closes editor only on success.
Removed unused isFormVisible, editingTreino, handleEdit from hook.
Kept __new__ sentinel for now.

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Emiya Kiritsugu <emiyakiritsugu3@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant