- Política de privacidade reescrita: tabela de dados/finalidades/fundamento
(inclui os pedidos de aula, inscrição e eventos com IP), prazos concretos,
subcontratantes, Google Maps e reviews, cookies. Termos e condições novos
(/home/termos), no rodapé e no sitemap. Campos [ENTRE PARÊNTESES RETOS]
e revisão por jurista pendentes antes de publicar no domínio real.
- Google Maps só carrega ao carregar em «Mostrar mapa» (map_click_to_load);
as fotos dos autores das reviews são guardadas pelo servidor em
uploads/reviews/ e servidas localmente (review_avatar_url).
- Retenção que a política declara, aplicada pelo cron (04:00): leads com
mais de 12 meses → lixeira; blocked_submissions e outbox de segurança
apagados aos 90 dias (trash_retention_sweep, auditado).
- Backoffice e login com tema claro/escuro/automático: data-bs-theme
aplicado no <head> antes do CSS (sem flash), escolha em localStorage,
segue o sistema em tempo real, color-scheme e theme-color para os dois.
Cores próprias passaram a variáveis do Bootstrap. lang="pt-PT".
Testado numa cópia da BD de produção: 72/72 verificações.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Pedido de aula experimental passa a ficar em trial_leads (por ginásio)
ANTES do email: sem SMTP o visitante já não vê «erro» e o pedido não se
perde. Gestão → Aulas experimentais: estados, notas, CSV (auditado),
apagar para a lixeira; aviso «sem email» quando o aviso não saiu.
- Aula experimental, inscrição e eventos usam o anti-spam do platform-tools
(honeypot, carimbo assinado com tempo mínimo, prova de JS, limite por IP,
pontuação de conteúdo) e o bloqueio de IP, em vez de honeypots locais.
Recusas ficam em blocked_submissions; resposta igual à de sucesso.
Falha aberto se o módulo rebentar.
- Checkbox de consentimento da aula experimental passa a ser guardada.
- Audit das escritas de conteúdo: criar/editar equipa, modalidades,
eventos, mensalidades, pedidos de inscrição, galerias, horário (incl.
arrastar no calendário), horas, contactos e ginásios, com antes/depois
campo a campo (audit_row/audit_change). Exportação CSV de inscrições
auditada.
- .table-responsive em todas as tabelas do backoffice.
- Migração: database/migration_20260926_trial_leads.sql (só cria tabelas).
Testado numa cópia da BD de produção: 63/63 verificações HTTP.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Estrutura multi-ginásio: as mesmas secções do site, conteúdo próprio por
ginásio, e cada um numa pasta da URL com o código postal da zona.
- migration_20260926_gyms: tabela gyms (pasta, nome, localidade, publicado,
principal, secções visíveis, título/imagem do header, SEO, galeria, Place ID,
página CrossFit) com o FitMe 3070 como ginásio 1 em /3070/; gym_id em team,
modalidades (o horário segue a modalidade), work_hours, memberships,
membership_leads e website_offer (tudo o existente → ginásio 1); events com
gym_id NULL = todos; fitme3070_info passa a uma linha por ginásio (id = gym).
- Site: /<pasta>/, /<pasta>/crossfit, /<pasta>/agendar|inscricao. Ginásio por
publicar → 404 para o público, pré-visualização (com faixa) para a equipa.
/ e /home → 301 para o ginásio principal (a manter a query); com mais de um
ginásio publicado, a raiz passa a uma página para escolher. Secções
desligadas não aparecem nem no menu; menu, canonical, JSON-LD, sitemap,
formulários, e-mails e reviews (Place ID e cache) são do ginásio.
- Backoffice: Gestão → Ginásios (criar/editar/apagar, secções, e «começar
com o conteúdo de» outro ginásio — cópias independentes) e o seletor
«A editar» no topo; equipa, modalidades, horários, horário de
funcionamento, mensalidades, pedidos, contactos e reviews trabalham sobre o
ginásio escolhido, e um registo de outro ginásio não abre.
- Modalidades passam para logo a seguir à galeria das instalações.
- Galeria sem cantos arredondados (raio da marca).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Ícones novos (Bootcamp, YourFit Core, Run3070, Total Workout, On Ramp, Jump)
do mesmo conjunto; só o LPO continua sem ícone no ficheiro de design.
- Os ícones fitme-*.svg passam a ir embutidos (modalidade_icon_html): cada
traço tem pathLength=1 e desenha-se ao aparecer, no hover e ao abrir o
cartão; cada família tem um movimento (levantar, soco, respirar, saltar,
chama, pedalar, correr). Outros ícones continuam <img>.
- No cartão de detalhe (desktop) o ícone e o nome deslizam até ao centro
vertical da coluna.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- A faixa de modalidades passa a ser um scroller a sério: toque, trackpad,
roda do rato, arrastar e setas; continua a deslizar sozinha (~20px/s) e
pára enquanto alguém interage, retomando 2,5s depois. Loop infinito sobre
uma cópia do conjunto (a posição é mantida em float — scrollLeft += 0.3
arredondava para zero).
- Em vez do «Saber mais», o cartão com descrição abre um painel que nasce do
próprio cartão e estica para o lado (para a esquerda junto à margem
direita), com inclinação 3D a seguir o rato; no telemóvel voa para o
centro com o fundo escurecido. O painel vive fora do scroller para o
overflow não o cortar.
- 14 ícones novos (SVG, traço 3) em uploads/modalidades/icons/fitme-*.svg.
- Títulos dos cartões em <h3>, h2#modalidades-title + aria-labelledby; sem
ícone não se gera <img> vazio.
- #modalidades entra só com opacidade: o transform deixado pela animação de
entrada prendia o fundo escurecido (position:fixed) dentro da secção.
- prefers-reduced-motion: os cartões de detalhe (equipa e modalidades)
ficam fora da regra global que reduzia as transições a 0,01ms — com ela
(ativa por defeito em Remote Desktop / Windows sem animações) o cartão
aparecia de repente em vez de esticar.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Horário de aulas: cartões mais pequenos e estreitos; a partir de 992px mostra
o dia anterior, hoje ao centro e o seguinte (a dar a volta à semana), com as
horas alinhadas e os dias laterais esbatidos. O JPG continua a semana toda.
- Horário de funcionamento: cartões compactos numa <dl>, ordenados por hora.
- Equipa: fundo no cinzento da parede do ginásio com juntas de blocos e grão
muito discretos (SVG inline).
- Tira o «FitMe 3070» do header e esconde a newsletter.
- Estrutura: um <main> em todas as páginas públicas (skip link aponta-lhe),
h2 por secção com aria-labelledby, h3 nos itens em vez de h4, sem secções
aninhadas, alts distintos na galeria e no h1 do CrossFit.
- robots.txt e sitemap.xml gerados com o domínio da instalação; SEO_NOINDEX
no .env tira uma cópia de staging dos motores de pesquisa.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
O cartão abre por cima da própria foto (mesmo sítio, tamanho e inclinação),
endireita-se e estica para o lado — para a esquerda nas fotos da ponta
direita — com o texto a entrar por trás. Aberto, inclina-se em 3D e desliza
uns píxeis na direção do rato; ao sair volta a dobrar-se para dentro da foto.
No telemóvel voa da foto para o centro (FLIP) e volta ao fechar.
- clip-path em px calculados no JS: o Chrome não interpola inset() com
calc(100% - …) e o recorte saltava em vez de esticar.
- O cartão é posicionado sem transição antes de abrir; senão a transição do
estado fechado arrancava primeiro e a abertura partia de valores antigos.
- Tira o «Saber mais» do cartão da equipa.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A Places API (New) não tem parâmetro de ordenação e devolve no máximo 5
reviews, por isso ordem e filtro aplicam-se a essas 5: relevância (ordem da
Google), mais recentes (publishTime) ou mais completas (texto mais longo), e
opcionalmente só quem tem foto de perfil. Mudar estas opções já não apaga a
cache — só uma nova chave ou Place ID obriga a um novo pedido pago.
Cartão: foto de 84px (ou inicial), nome, data e estrelas grandes em cima;
texto mais pequeno por baixo.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Contactos: nova página no backoffice (fitme3070_info) e 964 201 137 como
telefone principal; o telefone secundário só aparece quando existe.
- Equipa: título, aptidões/funções e formações; o cartão mostra foto, nome e
título e abre um cartão horizontal de detalhe (hover no desktop, toque no
telemóvel) sem mexer na grelha.
- Mensalidades: cartões editáveis com um destaque, modal de inscrição que
guarda o pedido (RGPD + estado + campos reservados para o CRM) e avisa o
ginásio por e-mail; lista de pedidos com estados, notas e CSV.
- Reviews Google via Places API (New), filtradas por classificação mínima e
em cache configurável; página de configuração com pesquisa do Place ID.
- Assets com ?v=<mtime>: site/assets é servido com cache imutável de 1 ano.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Plain-PHP fleet platform with id.andmore.pt SSO. Wires shared/platform-tools
as a submodule (platform_update, backups, git/migration tools) like the other
platforms.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>