Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
784069b
docs(it5): open It5-T01 branch — update CURRENT-STATE + CLAUDE.md
EmiyaKiritsugu3 Apr 21, 2026
5da5811
docs(it5): document pre-existing TS2882 regression in quality gates
EmiyaKiritsugu3 Apr 21, 2026
95ee4d6
fix(typecheck): restore src/types/css.d.ts deleted in PR #80 TS6 upgrade
EmiyaKiritsugu3 Apr 21, 2026
e12a927
docs(it5): mark TS2882 resolved in CURRENT-STATE quality gates
EmiyaKiritsugu3 Apr 21, 2026
f5a27a5
fix(it5): add requireAnyRole helper to auth.ts
EmiyaKiritsugu3 Apr 21, 2026
1746b75
fix(it5): add failing E2E negative auth test (TDD red)
EmiyaKiritsugu3 Apr 21, 2026
30e1742
fix(it5): gate /dashboard/treinos with requireAnyRole
EmiyaKiritsugu3 Apr 21, 2026
0dd8999
fix(it5): add failing unit tests for treinos actions (TDD red)
EmiyaKiritsugu3 Apr 21, 2026
2a1bb92
fix(it5): remove instrutorId from TreinoBaseSchema (server-derived)
EmiyaKiritsugu3 Apr 21, 2026
650febc
fix(it5): derive instrutorId from session in upsertTreinoAction
EmiyaKiritsugu3 Apr 21, 2026
751fcc7
fix(it5): remove instrutorId prop from TreinosManagementClient
EmiyaKiritsugu3 Apr 21, 2026
0ff04c6
fix(it5): remove redundant getUser and instrutorId prop from TreinosPage
EmiyaKiritsugu3 Apr 21, 2026
cca2b40
fix(it5): add ownership check to updateTreinoDayAction
EmiyaKiritsugu3 Apr 21, 2026
582f9e7
fix(it5): add ownership check to deleteTreinoAction
EmiyaKiritsugu3 Apr 21, 2026
40158d8
chore(it5): update CRITICAL-PATHS.md 18 → 19 scenarios
EmiyaKiritsugu3 Apr 21, 2026
8bff4a2
docs: update CURRENT-STATE.md for It5 completion
EmiyaKiritsugu3 Apr 21, 2026
7761e84
test(it5): add requireAnyRole unit tests to restore auth.ts 100% cove…
EmiyaKiritsugu3 Apr 22, 2026
b9035a3
fix(auth): address CodeRabbit review findings on PR #81
EmiyaKiritsugu3 Apr 22, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,8 @@ walkthrough.md
.remember/
.specify/

# Feature planning artifacts
specs/
# Feature planning artifacts (root-level only — not tests/e2e/specs/)
/specs/

# Dev scripts (not part of the build)
scripts/
Expand Down
8 changes: 6 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
# PWeb_Project Development Guidelines

Auto-generated from all feature plans. Last updated: 2026-04-19
Auto-generated from all feature plans. Last updated: 2026-04-21

## Active Technologies

- TypeScript 5 (strict mode, `useUnknownInCatchVariables`) + Next.js 15 App Router, Supabase Auth SSR (`@supabase/ssr`), Prisma 7, Zod 3 (feat/007-it5-instrutor-auth)
- PostgreSQL via Prisma (no migration for this spec) (feat/007-it5-instrutor-auth)

- TypeScript 5 (strict mode) + Playwright 1.59, Next.js 15 App Router, Supabase local CLI (feat/006-it4-instrutor-e2e)
- PostgreSQL via Prisma (local Supabase, ports 54321/54322) (feat/006-it4-instrutor-e2e)

Expand Down Expand Up @@ -42,10 +45,11 @@ TypeScript 5 (strict mode, `useUnknownInCatchVariables` enabled): Follow standar

## Recent Changes

- feat/007-it5-instrutor-auth: Added TypeScript 5 (strict mode, `useUnknownInCatchVariables`) + Next.js 15 App Router, Supabase Auth SSR (`@supabase/ssr`), Prisma 7, Zod 3

- feat/006-it4-instrutor-e2e: Added TypeScript 5 (strict mode) + Playwright 1.59, Next.js 15 App Router, Supabase local CLI

- 004-elite-workflow-setup: Added TypeScript 5 (strict mode, `useUnknownInCatchVariables`) + Node.js 20 + Next.js 15 App Router, Prisma 7, Supabase SSR, Zod 3, Genkit 1.31
- fix/telemetry-and-e2e-stability: Modernized Sentry to v10 + Next.js 15, implemented Privacy-First Replay, linked Supabase User IDs to observability, and repaired ESLint flat config.

<!-- MANUAL ADDITIONS START -->

Expand Down
84 changes: 52 additions & 32 deletions docs/CURRENT-STATE.md
Original file line number Diff line number Diff line change
@@ -1,35 +1,55 @@
# Current State — Five Star Academy

**Last Updated**: 2026-04-20
**Branch**: `main` (v0.7.0It4 merged PR #73)
**Version**: 0.7.0 (It4 completeINSTRUTOR workflow E2E, 18/18 passing)
**Last Updated**: 2026-04-21
**Branch**: `feat/007-it5-instrutor-auth` (It5all 12 tasks complete, PR ready)
**Version**: 0.7.0 (It4 baseIt5 hardening pending merge)
Comment on lines +3 to +5

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

CURRENT-STATE.md is already out of sync with this PR.

This file still reports 19 E2E scenarios and a pending npm run e2e, while the PR status here says 20/20 scenarios are passing and the PR is ready. Please refresh the counts/status here as well, or this handoff doc stops being trustworthy. Based on learnings, "Maintain and update docs/CURRENT-STATE.md at the start and end of every session to document progress and blockers".

Also applies to: 23-29, 65-68

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/CURRENT-STATE.md` around lines 3 - 5, Update the CURRENT-STATE.md
entries that are stale: open the document and change the "**Last Updated**" date
to the PR's current date, update the "**Branch**" and "**Version**" lines if
needed, and refresh the E2E scenario counts/status text to reflect 20/20
scenarios passing and remove the pending "npm run e2e" note; also propagate the
same corrections to the other occurrences mentioned (around lines showing E2E
counts at sections 23-29 and 65-68) so the handoff doc accurately matches the PR
status.


## What Works Today

| Feature | Status | Notes |
| ------------------------------------------- | ---------- | ----------------------------------------------------------------------------------------------- |
| Admin login | ✅ Working | Supabase Auth SSR |
| Student login (Portal do Aluno) | ✅ Working | Separate session |
| Admin dashboard | ✅ Working | GERENTE + RECEPCIONISTA |
| Financial routes (`/financeiro`, `/planos`) | ✅ Working | GERENTE-only gate |
| Student workout view | ✅ Working | `meus-treinos` |
| AI workout generator | ✅ Working | Genkit + Gemini |
| Student enrollment | ✅ Working | Admin creates aluno |
| Gamification (XP, streaks) | ✅ Working | Hook `use-workout-tracker` |
| Prisma migrations | ✅ Tracked | `prisma/migrations/` |
| ESLint quality gate | ✅ Done | 0 errors — `any` + unused vars |
| TypeScript typecheck | ✅ Clean | 0 errors (strict mode) |
| AI workout feedback (US06) | ✅ Done | `WorkoutSession.tsx` — Genkit call + try/catch fallback + feedback card |
| Unit tests | ✅ Passing | 22/22 (Vitest) |
| Ops documentation | ✅ Done | Runbook, SLOs, threat model |
| Process documentation | ✅ Done | RFC + Postmortem templates |
| Local E2E stack | ✅ Done | `supabase start` (Docker) |
| E2E seed script | ✅ Done | `prisma/seed-e2e.ts` (5 fixtures: 4 users + 1 treino with 2 exercícios) |
| Playwright E2E suite | ✅ Done | 18 scenarios (+ instrutor-workflow: INSTRUTOR assigns workout → ALUNO sees "Do Personal" badge) |
| CI E2E job | ✅ Green | 18/18 passing locally (It4); 17/17 in last CI (PR #72); PR pending |
| Sentry error tracking | ✅ Active | DSN + auth token set in Vercel; source maps (92) uploaded on every build |
| Structured logging | ✅ Done | `src/lib/logger.ts` (Logger wrapper, Sentry-aware) |
| Dependencies | ✅ Updated | All patch/minor bumped via PR #70; lockfile clean |
| Feature | Status | Notes |
| ------------------------------------------- | ---------- | ---------------------------------------------------------------------------------------------------- |
| Admin login | ✅ Working | Supabase Auth SSR |
| Student login (Portal do Aluno) | ✅ Working | Separate session |
| Admin dashboard | ✅ Working | GERENTE + RECEPCIONISTA |
| Financial routes (`/financeiro`, `/planos`) | ✅ Working | GERENTE-only gate |
| Student workout view | ✅ Working | `meus-treinos` |
| AI workout generator | ✅ Working | Genkit + Gemini |
| Student enrollment | ✅ Working | Admin creates aluno |
| Gamification (XP, streaks) | ✅ Working | Hook `use-workout-tracker` |
| Prisma migrations | ✅ Tracked | `prisma/migrations/` |
| ESLint quality gate | ✅ Done | 0 errors — `any` + unused vars |
| TypeScript typecheck | ✅ Clean | 0 errors (strict mode) |
| AI workout feedback (US06) | ✅ Done | `WorkoutSession.tsx` — Genkit call + try/catch fallback + feedback card |
| Unit tests | ✅ Passing | 32/32 (Vitest — +10 for It5 treinos auth tests) |
| Ops documentation | ✅ Done | Runbook, SLOs, threat model |
| Process documentation | ✅ Done | RFC + Postmortem templates |
| Local E2E stack | ✅ Done | `supabase start` (Docker) |
| E2E seed script | ✅ Done | `prisma/seed-e2e.ts` (5 fixtures: 4 users + 1 treino with 2 exercícios) |
| Playwright E2E suite | ✅ Done | 19 scenarios (18 It4 + instrutor-auth-negative: RECEPCIONISTA/ALUNO blocked from /dashboard/treinos) |
| CI E2E job | ✅ Green | 18/18 passing locally (It4); 17/17 in last CI (PR #72); PR pending |
| Sentry error tracking | ✅ Active | DSN + auth token set in Vercel; source maps (92) uploaded on every build |
| Structured logging | ✅ Done | `src/lib/logger.ts` (Logger wrapper, Sentry-aware) |
| Dependencies | ✅ Updated | All patch/minor bumped via PR #70; lockfile clean |

## It5 Progress (007-it5-instrutor-auth)

**Spec**: `specs/007-it5-instrutor-auth/` — all Phase 0–1 artifacts complete (spec, plan, research, data-model, quickstart, tasks)
**12 tasks — ALL COMPLETE** ✅

| Task | Description | Status |
| ---- | ------------------------------------------------------------- | ----------- |
| T001 | Add `requireAnyRole` to `src/lib/auth.ts` | ✅ Complete |
| T002 | Create E2E negative test (RECEPCIONISTA/ALUNO blocked) | ✅ Complete |
| T003 | Gate `/dashboard/treinos` with `requireAnyRole` | ✅ Complete |
| T004 | Write unit tests for `upsertTreinoAction` (TDD red) | ✅ Complete |
| T005 | Remove `instrutorId` from `TreinoBaseSchema` | ✅ Complete |
| T006 | Harden `upsertTreinoAction` (derive instrutorId from session) | ✅ Complete |
| T007 | Remove `instrutorId` prop from `TreinosManagementClient` | ✅ Complete |
| T008 | Remove `getUser` + `instrutorId` prop from `TreinosPage` | ✅ Complete |
| T009 | Write ownership unit tests (TDD red) | ✅ Complete |
| T010 | Add ownership check to `updateTreinoDayAction` | ✅ Complete |
| T011 | Add ownership check to `deleteTreinoAction` | ✅ Complete |
| T012 | Update `CRITICAL-PATHS.md` 18 → 19 scenarios | ✅ Complete |

## What Is Incomplete

Expand All @@ -42,10 +62,10 @@
## Quality Gates (current status)

```
npm run typecheck → ✅ 0 errors
npm run typecheck → ✅ 0 errors (TS2882 fixed: src/types/css.d.ts restored)
npm run lint → ✅ 0 errors
npm run test → ✅ 22/22 passing
npm run e2e → ✅ 18/18 passing (local, 2026-04-19 — It4)
npm run test → ✅ 32/32 passing (+10 It5 auth tests)
npm run e2e → ⏳ 19 scenarios (18 confirmed It4; #19 needs E2E run against local stack)
npm run build → ✅ production build succeeds
```

Expand All @@ -58,7 +78,7 @@ npm run build → ✅ production build succeeds
- **Validation**: Zod 3
- **AI**: Google Genkit 1.32 + Gemini 2.5 Flash
- **Styling**: Tailwind CSS 4 + Shadcn/UI
- **Testing**: Vitest 4 (5 files, 22 unit tests) + Playwright 1.59 (18 E2E scenarios)
- **Testing**: Vitest 4 (6 files, 32 unit tests) + Playwright 1.59 (19 E2E scenarios)
- **CI**: GitHub Actions (quality + test + e2e jobs)
- **Local E2E DB**: Supabase CLI (`supabase start` → ports 54321/54322)

Expand All @@ -69,7 +89,7 @@ npm run build → ✅ production build succeeds
| `src/app/dashboard/` | Admin portal pages |
| `src/app/aluno/` | Student portal pages |
| `src/lib/actions/` | Server Actions (auth, alunos, treinos, financeiro) |
| `src/lib/auth.ts` | `requireRole()` helper |
| `src/lib/auth.ts` | `requireRole()` + `requireAnyRole()` (It5 — live) |
| `src/services/` | Business logic (XP, streaks) |
| `src/ai/flows/` | Genkit AI flows |
| `prisma/schema.prisma` | DB schema |
Expand Down
4 changes: 1 addition & 3 deletions src/app/aluno/meus-treinos/meus-treinos-client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,8 @@ export default function MeusTreinosClient({
try {
const res = await upsertTreinoAction({
...treinoData,
id: editingTreino?.id,
...(editingTreino ? { id: editingTreino.id } : {}),
alunoId: userId,
instrutorId: userId,
});

if (res.success) {
Expand Down Expand Up @@ -192,7 +191,6 @@ export default function MeusTreinosClient({

const res = await upsertTreinoAction({
alunoId: userId,
instrutorId: undefined,
objetivo: workout.nome,
exercicios: novosExercicios,
diaSemana: isDayOccupied ? null : diaSugerido,
Expand Down
13 changes: 3 additions & 10 deletions src/app/dashboard/treinos/page.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,11 @@
import { prisma } from '@/lib/prisma';
import { createClient } from '@/utils/supabase/server';
import { requireAnyRole } from '@/lib/auth';
import { PageHeader } from '@/components/page-header';
import TreinosManagementClient from './treinos-client';
import type { Aluno } from '@/lib/definitions';

export default async function TreinosPage() {
const supabase = await createClient();
const {
data: { user },
} = await supabase.auth.getUser();

if (!user) {
return <div>Não autorizado</div>;
}
await requireAnyRole(['INSTRUTOR', 'GERENTE']);

// Buscar todos os alunos para a seleção via Prisma
const alunosPrisma = await prisma.aluno.findMany({
Expand Down Expand Up @@ -42,7 +35,7 @@ export default async function TreinosPage() {
title="Gestão de Treinos"
description="Monte treinos manualmente ou use a IA para gerar sugestões personalizadas para os alunos."
/>
<TreinosManagementClient initialAlunos={alunosData} instrutorId={user.id} />
<TreinosManagementClient initialAlunos={alunosData} />
</>
);
}
10 changes: 1 addition & 9 deletions src/app/dashboard/treinos/treinos-client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -316,13 +316,7 @@ function PlanoGeradoParaEdicao({
);
}

export default function TreinosManagementClient({
initialAlunos,
instrutorId,
}: {
initialAlunos: Aluno[];
instrutorId: string;
}) {
export default function TreinosManagementClient({ initialAlunos }: { initialAlunos: Aluno[] }) {
const { toast } = useToast();
const [selectedAlunoId, setSelectedAlunoId] = useState<string | null>(null);
const [objetivo, setObjetivo] = useState('');
Expand Down Expand Up @@ -381,7 +375,6 @@ export default function TreinosManagementClient({
try {
const res = await upsertTreinoAction({
alunoId: selectedAlunoId,
instrutorId,
objetivo,
exercicios: exercicios as Exercicio[],
diaSemana: null,
Expand Down Expand Up @@ -430,7 +423,6 @@ export default function TreinosManagementClient({
for (const workout of planoEditado.workouts) {
await upsertTreinoAction({
alunoId: selectedAluno.id,
instrutorId,
objetivo: workout.nome,
exercicios: workout.exercicios.map((ex) => ({
nomeExercicio: ex.nomeExercicio,
Expand Down
Loading
Loading