Documenta como o cursos.overia.com.br e construido (LearnHouse 1.3.6 community
no NAS4, login pelo Keycloak via oauth2-proxy e ponte, tema overia injetado pelo
nginx, aulas por proxy /aulas), as armadilhas ja encontradas, o runbook de
publicacao, rollback, backup e atualizacao, e as decisoes e pendencias.
learnhouse-upstream.md resume o repositorio e a documentacao oficiais e marca onde
a doc diverge do codigo da imagem (cookies LH_*, politica de login por organizacao).
deploy/publicar-tema.sh publica deploy/theme e o nginx.prod.conf com nginx -t e
volta automatica; recebe host, porta, usuario e senha por variaveis de ambiente.
O repositorio e publico: nenhum IP, porta, usuario, conta ou segredo nos arquivos.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
theme-toggle.js: botao no canto inferior esquerdo alterna automatico -> claro ->
escuro, guarda a escolha em localStorage e aplica data-theme em <html> antes da
pintura. O CSS escuro agora vale tanto pelo sistema (sem escolha manual) quanto
pela escolha "escuro"; as 26 regras sao as mesmas, so muda o prefixo.
Escuro para o conteudo das aulas (.markdown-body do github-markdown-css fixava
fundo branco): texto, links, codigo, citacoes e tabelas.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
O Gitea nao envia Access-Control-Allow-Origin, entao o navegador bloqueava a
leitura do Markdown a partir de cursos.overia.com.br e toda aula mostrava
"Failed to fetch". Novo /aulas/<caminho>.md no nginx busca o arquivo no Gitea e o
serve no proprio dominio. So aceita GET/HEAD de .md sob courses/ do repositorio
ai-bot/cursos, rejeita "..", resolve o DNS em tempo de execucao (o nginx nao deixa
de subir se o Gitea estiver fora) e nao repassa cookies.
No banco, as 8 aulas passaram a apontar para /aulas (backup das linhas em
~/backups/learnhouse-20261003 no NAS4). README: GITEA_RAW_BASE agora deve ser
https://cursos.overia.com.br/aulas, senao uma nova publicacao desfaz a correcao.
O conf tambem referencia theme-toggle.js, que entra no commit seguinte.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
As duas palavras usam a mesma fonte (Red Hat Display 600), tamanho (1.1rem) e
espacamento; "cursos" segue em verde e "overia" na cor do texto.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Variante escura (prefers-color-scheme: dark) com a paleta de overia.com.br
escuro: tokens shadcn em HSL e remapeamento das cores fixas do Tailwind
(bg-white, text-gray-*, border-gray-*, text-black/NN). Auditoria automatica
em 8 telas (home, cursos, library, podcasts, comunidades, playgrounds, curso e
aula): nenhum fundo claro e nenhum texto abaixo de contraste 3.
Marca do cabecalho em duas linhas: "cursos" (mono, verde) sobre "overia".
Logo da organizacao trocado pelo simbolo transparente, que serve aos dois temas.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
CSS e fontes copiados de overia.com.br (tema claro): paleta verde/tinta,
Red Hat Display/Text e JetBrains Mono servidas localmente, cabecalho branco com
linha fina e marca "overia", botoes verdes, cartoes com contorno. O LearnHouse
nao tem modo escuro, entao so o claro e aplicado.
O nginx serve ./theme em /overia-theme/ (volume novo no compose) e injeta o link
da folha antes de </head>. A versao no ?v= deve subir a cada mudanca: o
Cloudflare guarda respostas, inclusive 404, por horas. Nao recriar a pasta
./theme no servidor (copiar o conteudo para dentro) ou o volume monta vazio.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
nginx.prod.conf: /login e /signup passam pelo Keycloak (cadastro direto via
/registrations), /sso/login e /logout vao para a ponte, pre-busca ?_rsc do
Next.js responde 204 (senao /oauth2/start sobrescreve o cookie PKCE e o login
falha), botao Sair e interceptacao do Sign Out injetados so para quem tem
LH_access.
docker-compose.override.yml: oauth2-proxy (client cursos, realm overia) e
sso-bridge. Aplicar com: docker compose -p xen-learnhouse up -d --no-deps.
Os segredos ficam em oauth2-proxy.env, fora do repositorio.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Sidecar que roda com o codigo do proprio LearnHouse. Em /sso/login confirma a
identidade perguntando ao oauth2-proxy (nunca confia em cabecalho do cliente),
acha ou cria o usuario pelo e-mail verificado e emite LH_access, LH_refresh e
LH_session, que o frontend exige para considerar o usuario logado. /sso/logout
limpa os cookies e encerra a sessao no Keycloak.
Redirecionamento pos-login restrito a caminhos internos (padrao: home).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
- spec: uso correto e' 'python -m scripts.publish', nao o caminho direto do
arquivo (imports absolutos quebram sem -m); ajusta texto do --dry-run pra
descrever o que ele realmente imprime (arvore + URLs, nao payload
completo); deixa explicito que a URL em Referencias e' link Markdown.
- plan: dono real do repo Gitea e' ai-bot/cursos, nao ia-bot/cursos.
- pyproject.toml: descricao real do projeto.
- README.md novo: o que e' o repo, estrutura, variaveis de .env, comando de uso.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
raise_for_status() sozinho so mostra status code, sem o corpo do erro 4xx/5xx
da API - dificulta debug. Centralizado num helper _raise_for_status pra nao
repetir try/except em cada metodo.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Bug critico: ao publicar um curso ja existente com --publish, o codigo
atualizava metadados mas continuava chamando create_chapter/create_markdown_activity
do zero, duplicando a estrutura (ja aconteceu em producao, dados orfaos
corrigidos manualmente via API).
Agora, se o curso ja existe: so atualiza metadados; se publish=True, busca
a estrutura real via get_course_chapters (novo metodo, GET /courses/{uuid}/meta)
e publica so as atividades ainda nao publicadas, sem recriar nada.
Decisao: ignora atividades ja publicadas (nao rechama publish_activity nelas)
em vez de rechamar por simplicidade - evita chamadas HTTP redundantes sem
custo de complexidade adicional.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Remove seção [project.scripts] que causava erro de build ao procurar
src/cursos_overia/__init__.py (não commitado). Adiciona [tool.uv] package=false
para evitar tentar buildá-lo como pacote instalável.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>