Aplicação web para gerenciar reservas de salas e equipamentos, desenvolvida como projeto integrado das disciplinas:
- PWEB2 — Programação para Web 2 (implementação da aplicação)
- Engenharia de Requisitos de Software (levantamento, especificação e validação dos requisitos)
Status: ✅ em produção na Vercel → https://sira-jet.vercel.app
Sprint 1 (25/25 user stories) foi um protótipo em JavaScript puro (ES Modules) + Vite, preservado em
legacy/para histórico. A Sprint 2 (fase atual) migrou o produto para Next.js (App Router) + TypeScript + Supabase e adicionou: 2FA (TOTP) com exigência no acesso (AAL2), imagem de recurso, reserva temporária (hold), calendário/ aprovações/notificações revisados e responsividade desktop/tablet/celular.
🔗 Aplicação: https://sira-jet.vercel.app · 📸 prévia da tela de login:
| Camada | Ferramenta | Versão |
|---|---|---|
| Framework / dev server | Next.js (App Router, Server Components, Server Actions) | 16.x |
| Linguagem | TypeScript (strict) |
^5 |
| UI | React | 19.x |
| Estilo | Tailwind CSS v4 + Material Design 3 (tokens) | ^4 |
| Componentes | shadcn/ui (primitivos Radix) + next-themes |
— |
| Backend / Auth / DB | Supabase (Postgres + Auth + RLS + RPCs + Storage) | @supabase/ssr ^0.12 · js ^2.108 |
| Formulários / Validação | React Hook Form + Zod | ^7 / ^4 |
| Gerência de estado | TanStack Query (servidor) + Zustand (UI global) + Context API | ^5 / ^5 |
| Testes | node:test (unit) · Vitest + Testing Library (componente) · Cucumber (BDD pt-BR) · Playwright (E2E/a11y) |
— |
| Qualidade | ESLint + Prettier + Husky + lint-staged | ^9 / ^3 |
| Deploy | Vercel | — |
- Node.js 22/24 LTS — fixado em
.nvmrc. (Na Vercel, use 22.x se a 24 ainda não estiver disponível.) - npm 11+ (já vem bundled com o Node).
- Uma conta/projeto Supabase (Postgres + Auth + Storage).
- Recomendado:
nvmpara alternar versões.
nvm install # instala a versão do .nvmrc
nvm use # ativa a versão correta# 1. Instale as dependências (cria node_modules/ e configura o Husky)
npm install
# 2. Configure as variáveis de ambiente (copie o modelo e preencha)
cp .env.example .env.local
# Preencha NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_ANON_KEY,
# SUPABASE_SERVICE_ROLE_KEY e NEXT_PUBLIC_SITE_URL (ver .env.example).
# 3. Suba o dev server (Next.js + Turbopack, HMR)
npm run devA aplicação estará disponível em http://localhost:3000.
O script
preparedopackage.jsonrodahuskyautomaticamente após onpm install, registrando os hooks de pre-commit. OSUPABASE_SERVICE_ROLE_KEYé server-only (provisionamento de contas) — nunca prefixe comNEXT_PUBLIC_nem comite (já está no.gitignore).
| Script | O que faz |
|---|---|
npm run dev |
Inicia o servidor de desenvolvimento do Next.js (Turbopack, HMR) na porta 3000 |
npm run build |
Gera o build de produção (.next/) |
npm run start |
Serve o build de produção localmente |
npm test |
Roda unit + componente + BDD em sequência |
npm run test:unit |
Testes unitários da lógica pura (src/lib/) com node:test |
npm run test:component |
Testes de componente React com Vitest + Testing Library |
npm run test:bdd |
Cenários BDD (Gherkin pt-BR) com Cucumber |
npm run test:e2e |
Testes E2E com Playwright |
npm run test:a11y |
Auditoria de acessibilidade (Playwright + @axe-core/playwright) |
npm run lint |
Roda o ESLint |
npm run lint:fix |
ESLint aplicando correções automáticas |
npm run format |
Formata todos os arquivos com Prettier |
npm run prepare |
Instala os hooks do Husky (executado pelo npm após o install) |
O projeto tem duas fases, ambas preservadas para histórico:
- Sprint 2 (atual) — aplicação em Next.js + TypeScript + Supabase.
- Sprint 1 (legado) — protótipo em Vanilla JS + Vite, preservado em
legacy/(não é mais buildado).
As convenções de desenvolvimento (padrões arquiteturais, gotchas, contrato de IA) vivem em
AGENTS.md.
.
├── src/
│ ├── app/ # App Router (RSC-first)
│ │ ├── layout.tsx · globals.css # raiz: fontes, ThemeProvider, Providers (TanStack), VLibras; tokens M3
│ │ ├── (auth)/ # grupo PÚBLICO (sem shell)
│ │ │ ├── login/ # page.tsx · login-form.tsx · actions.ts
│ │ │ ├── cadastro/ # auto-serviço de cadastro de professor
│ │ │ └── redefinir-senha/
│ │ ├── verificar-2fa/ # desafio TOTP no acesso (enforcement AAL2 — F-39)
│ │ └── (app)/ # grupo PROTEGIDO (shell + RBAC)
│ │ ├── layout.tsx · loading.tsx # requireProfile() + navegação por perfil; skeleton de rota
│ │ ├── calendario/ # grade semanal 7d × 12h
│ │ ├── nova-reserva/ # assistente (wizard) em 4 passos + reserva temporária (hold)
│ │ ├── minhas-reservas/ # lista + [id]/ (detalhe) + edição/cancelamento + CSV
│ │ ├── notificacoes/ # central de notificações
│ │ ├── painel/ # KPIs admin (dashboard)
│ │ ├── aprovacoes/ # fila admin — aprovar/recusar (decide série recorrente)
│ │ ├── salas/ · equipamentos/ # catálogos (consomem _resources/) + imagem de recurso
│ │ ├── usuarios/ # gestão de usuários + solicitações de cadastro
│ │ ├── configuracoes/ # perfil · preferências · segurança/2FA · notificações · zona de risco
│ │ └── _resources/ # componentes/actions compartilhados de salas + equipamentos
│ ├── components/
│ │ ├── shell/ # app-shell · sidebar · header · nav-config · user-menu · theme-toggle · logout
│ │ ├── ui/ # primitivos shadcn/Radix (button, input, label, form, dropdown-menu)
│ │ └── providers.tsx · theme-provider.tsx · vlibras.tsx
│ ├── lib/ # DOMÍNIO PURO (sem framework, testável com node:test)
│ │ ├── auth.ts · validation.ts · utils.ts · mfa.ts
│ │ ├── reservation.ts · my-reservations.ts · holds.ts · calendar.ts · calendar-events.ts
│ │ ├── approvals.ts · dashboard.ts · notifications.ts · resources.ts · users.ts · preferences.ts
│ │ └── supabase/ # client · server · admin (service-role) · middleware · database.types
│ ├── schemas/ # Zod compartilhado client+servidor (auth, profile, reservation, resource, user)
│ ├── hooks/ # use-media-query · use-mounted · queries/ (TanStack Query)
│ ├── stores/ # Zustand — ui-store (colapso da sidebar, persistido)
│ └── proxy.ts # middleware Next 16 — refresh de sessão + proteção de rota + gate AAL2
├── supabase/migrations/ # DDL versionada (idempotente, nunca reeditada)
│ ├── 0001_initial_schema · 0002_harden_security_definer_grants · 0003_seed_reference_data
│ ├── 0004_availability_functions · 0005_reservation_submitted_event_trigger
│ └── 0006_reservation_count_aggregation_rpcs · 0007_resource_image_storage · 0008_reservation_holds
├── tests/
│ ├── *.test.ts # unitário (node:test) — regras puras de src/lib (+ loader.mjs, tsconfig.json)
│ ├── components/ # componente — Vitest + Testing Library
│ ├── features/ # BDD Cucumber (pt-BR): *.feature + steps/ + support/ (World em memória)
│ └── e2e/ # Playwright — smoke, a11y, perf, image-upload, hold
├── docs/ # espinha de rastreabilidade (o "porquê/o quê/como")
│ ├── requirements/ # RF-* / RNF-*
│ ├── backlog/ # epics/ · features/ · sprints/ · glossario.md
│ ├── specs/ # análise/projeto navegável por feature
│ ├── planning/adrs/ # ADR-001 … ADR-010 (decisões arquiteturais)
│ └── runbooks/ · mockups/ · reports/
├── public/screenshots/ # capturas (login.png)
├── legacy/vite-app/ # Sprint 1 (histórico — não buildado)
├── PRD.md · AGENTS.md (↔ CLAUDE.md symlink) # produto + contrato de desenvolvimento (humano/IA)
├── .env.example # contrato de variáveis (Supabase + NEXT_PUBLIC_SITE_URL)
└── next.config.ts · tsconfig.json · eslint.config.mjs · postcss.config.mjs
· vitest.config.ts · vitest.setup.ts · playwright.config.ts · cucumber.cjs
Entrega original (25/25 user stories), preservada para referência em
legacy/— não é mais buildada. A árvore abaixo descreve o layout daquela fase.
legacy/ (era a raiz do projeto na Sprint 1)
├── .github/workflows/
│ ├── ci.yml # Valida formatação e build em PRs e push em develop
│ └── deploy.yml # Publicava no GitHub Pages quando uma release era publicada
├── public/
│ ├── icons/ # Ícones SVG usados pela aplicação
│ └── screenshots/ # Capturas de tela do produto
├── src/
│ ├── components/
│ │ ├── modal.js # API de modais (createModal/openModal/closeModal) + listener global Esc
│ │ └── sidebar.js # Sidebar contextual com badges, userPill, logout e toggle de tema
│ ├── data/
│ │ ├── logins.json # Seed do usuário admin
│ │ ├── seed.json # Seeds vazios para rooms / reservations / notifications / approvals
│ │ └── store.js # Camada de dados: AUTH + persistência por usuário + aprovações cross-user
│ ├── modules/
│ │ ├── calendar.js # Grade semanal 7d × 12h com eventos por status (US-13)
│ │ └── novaReserva.js # Busca de salas + criação de reserva com anti-conflito (US-14/15)
│ ├── utils/
│ │ ├── dom.js # Factories: el, render, btn, badge, tableRow, toast, confirm
│ │ └── fp.js # Helpers funcionais: filterByText, computeStats (reduce), initials, statusBadge…
│ ├── main.js # Entry point — bootstrap, autenticação inline, roteador e drawer mobile
│ └── *.css # auth.css, home.css, style.css (CSS Variables + dark mode)
├── index.html # Entry point HTML do Vite
└── vite.config.js # Configuração do Vite (base condicional via env GITHUB_PAGES)
Notas de domínio (Sprint 1):
src/components/continha os blocos visuais reutilizáveis (sidebar, modal).src/modules/tinha uma página por arquivo — cadarenderXera registrado emPAGE_RENDERERSnomain.jse roteado por URL viapushState+popstate.src/data/store.jsera a única fonte de verdade para LocalStorage, com particionamento por e-mail (sira_db/<email>/<colecao>.json) e consolidação automática quando o usuário logado era admin. (Substituído por Supabase + RLS na Sprint 2 — ver ADR-001.)
O fluxo de qualidade funciona assim:
- Antes do commit (local): o hook
pre-commitdo Husky chamanpx lint-staged, que roda ESLint + Prettier apenas nos arquivos alterados — segundo a configuraçãolint-stageddopackage.json:*.{ts,tsx,js,jsx}→eslint --fix+prettier --write*.{json,css,md}→prettier --write
- Build:
npm run build(Next.js) valida tipos (strict) e compila as rotas. - Testes:
npm test(unitário + componente + BDD) e Playwright (test:e2e/test:a11y).
No CI (GitHub Actions), o workflow
ci.ymlroda em cada PR: lint + prettier + build +npm test. O antigodeploy.yml(GitHub Pages, era Sprint 1) foi removido — na Sprint 2 o deploy de produção é nativo da Vercel (ver a seção Deploy).
Produção: https://sira-jet.vercel.app
O deploy é na Vercel (Next.js), conectada ao repositório GitHub: cada push
na branch main dispara o build de produção e cada PR gera um preview. O
passo a passo completo — variáveis de ambiente, URLs de autenticação do Supabase
e SMTP — está no runbook:
➡️ docs/runbooks/deploy-vercel.md
Variáveis necessárias (Project Settings → Environment Variables):
NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_ANON_KEY,
SUPABASE_SERVICE_ROLE_KEY (secreta, server-only) e NEXT_PUBLIC_SITE_URL.
Modelo em .env.example.
Headers de segurança (X-Frame-Options, nosniff, Referrer-Policy, Permissions-Policy) já vêm configurados em
next.config.ts.
Modelo simplificado, com proteções na main:
| Branch | Papel |
|---|---|
main |
Branch protegida. Recebe apenas merges via PR de develop. Origem das releases. |
develop |
Branch de integração contínua. CI roda em todo push. |
feature/* |
Branches de desenvolvimento. Saem de develop e voltam via PR para develop. |
Convenção de commits: mensagens curtas em português, com prefixos
estilo Conventional Commits — feat, fix, chore, ci, docs,
refactor, test.
O backlog do SIRA foi quebrado em 25 user stories distribuídas em
13 épicos e divididas entre os 5 membros do time. A sequência de
implementação está descrita em docs/reports/sprint-1/sequencia_us.pdf
(quem desbloqueia quem). O detalhamento individual de cada membro está
em docs/team-tasks/sprint-1/.
| US | Descrição | Status | PR |
|---|---|---|---|
| US-01 | Configurar projeto base com Vite | ✅ Mergeada | #125 |
| US-02 | Criar utilitários funcionais e estilos | ✅ Mergeada | #126 |
| US-03 | Permitir login pelo e-mail institucional | ✅ Mergeada | #127 |
| US-04 | Permitir solicitação de cadastro | ✅ Mergeada | #128 |
| US-05 | Permitir logout do sistema | ✅ Mergeada | #127 (T-05.2 — logout() em store.js) · #134 (T-05.1 — botão "Sair" no userPill) |
| US-09 | Alternar tema claro/escuro | ✅ Mergeada | #134 (T-09.1/T-09.2 — toggle + persistência) · #154 (T-09.3 — restauração no bootstrap) |
Conclusão: 6 / 6 user stories concluídas.
| US | Descrição | Status | PR |
|---|---|---|---|
| US-06 | Sidebar contextual com badges e filtro por role | ✅ Mergeada | #134 |
| US-07 | Roteamento por URL com pushState + popstate |
✅ Mergeada | #144 |
| US-08 | Drawer mobile com hambúrguer e tabelas responsivas | ✅ Mergeada | #145 |
| US-13 | Calendário semanal 7d × 12h com eventos por status | ✅ Mergeada | #147 |
| US-25 | Sistema centralizado de modais (create/open/close) | ✅ Mergeada | #149 |
Conclusão: 5 / 5 user stories concluídas.
| US | Descrição | Status | PR |
|---|---|---|---|
| US-10 | LocalStorage isolado por usuário (sira_db/<email>/...) |
✅ Mergeada | #143 |
| US-11 | Sincronização aprovação → reserva → notificação | ✅ Mergeada | #143 |
| US-12 | Dashboard administrativo com KPIs em tempo real | ✅ Mergeada | #161 |
| US-24 | Caixa de notificações com marcação como lidas | ✅ Mergeada | #162 |
Conclusão: 4 / 4 user stories concluídas.
| US | Descrição | Status | PR |
|---|---|---|---|
| US-14 | Busca de salas com filtros e anti-conflito de horário | ✅ Mergeada | #152 |
| US-15 | Detalhes da sala + reserva 1-clique com aprovação | ✅ Mergeada | #152 |
| US-16 | Listar minhas reservas com filtros e busca textual | ✅ Mergeada | #159 |
| US-17 | Ver, editar e cancelar reservas pendentes | ✅ Mergeada | #159 |
| US-18 | Exportar reservas em CSV | ✅ Mergeada | #159 |
Conclusão: 5 / 5 user stories concluídas.
| US | Descrição | Status | PR |
|---|---|---|---|
| US-19 | Fila consolidada de aprovações pendentes | ✅ Mergeada | #163 |
| US-20 | Aprovar / recusar reservas com notificação ao autor | ✅ Mergeada | #163 |
| US-21 | CRUD de salas com filtros, recursos e status | ✅ Mergeada | #164 |
| US-22 | CRUD de usuários com perfis professor/admin | ✅ Mergeada | #170 |
| US-23 | Aprovar/recusar solicitações de cadastro pendentes | ✅ Mergeada | #166 |
Conclusão: 5 / 5 user stories concluídas.
| Bloco | Responsável | Concluído | Total |
|---|---|---|---|
| Fundação + Auth + Tema | Gabriel Marques | 6 | 6 |
| Shell + Modais + Calendário | Ian Lucas | 5 | 5 |
| Persistência + Dashboard | Igor Gimenez | 4 | 4 |
| Reservas (Nova + CRUD) | José Henrique | 5 | 5 |
| Administração | Pedro Sales | 5 | 5 |
| Total | — | 25 | 25 |
⚠️ A tabela e os blocos acima refletem a entrega original em Vanilla JS + Vite. O projeto foi migrado para Next.js + TypeScript + Supabase; a lista abaixo reflete as funcionalidades atuais.
Funcionalidades implementadas (Next.js + Supabase):
- Autenticação institucional (
@ifpb.edu.br): login, cadastro com aprovação, logout, recuperação de senha por e-mail, MFA/TOTP opcional; sessão via Supabase Auth (verificação local de JWT comgetClaims). - Proteção de rotas por perfil (professor/admin) via
proxy.ts+ guards no servidor. - Calendário semanal 7d × 12h com eventos por status; Nova Reserva (wizard com busca anti-conflito e reserva temporária / hold do recurso durante a solicitação).
- CRUD das próprias reservas (listar, filtrar, ver detalhe, editar, cancelar, exportar CSV).
- Painel administrativo com KPIs (agregação no banco via RPC).
- Central de notificações (marcar individual/todas) com cache via TanStack Query.
- Fila de aprovações (aprovar/recusar com motivo → notificação ao solicitante; bloqueio de auto-aprovação).
- Gestão de recursos — CRUD de salas e equipamentos, agora com upload de imagem (Supabase Storage) exibida nos cards.
- Gestão de usuários e revisão de solicitações de cadastro (provisionamento via service-role).
- Configurações da conta — perfil, tema (claro/escuro/sistema), densidade, reduzir-animações, preferências de notificação, segurança e zona de risco.
- Acessibilidade (WCAG 2.2 AA, axe 0 violações), responsividade (mobile-first) e VLibras (tradutor de Libras) em todas as páginas.
| Membro | GitHub | Bloco |
|---|---|---|
| Gabriel Marques | @GabeMarques-Intetsu | Fundação + Autenticação + Tema |
| Ian Lucas | @IanGds | Shell + Navegação + Modais + Calendário |
| Igor Gimenez | @igorgmnzmonte | Persistência + Dashboard + Notificações |
| José Henrique | @jhenriquecs | Reservas (Nova Reserva + CRUD + CSV) |
| Pedro Sales | @pedro-sls | Administração (Aprovações + Salas + Usuários) |
Projeto acadêmico desenvolvido no IFPB para as disciplinas de Programação para Web 2 e Engenharia de Requisitos de Software.
