Skip to content

vyk1/crossforge

Repository files navigation

CrossForge 🧩

Sistema de cruzadinhas temáticas, open source e 100% client-side. Importe um JSON ou CSV com pares palavra → dica, gere um grid interativo e jogue no browser — sem backend, sem dependências externas além do React.

Stack Build Tests License


Funcionalidades

  • Import flexível — JSON ou CSV com palavra,dica
  • Gerador de layout — algoritmo de encaixe automático, sem dependência npm
  • Grid interativo — navegação por teclado e toque, highlight da palavra ativa
  • Revelar palavra aleatória — dica de socorro sem revelar tudo
  • Verificação — feedback visual célula a célula (correto / errado / revelado)
  • Compartilhamento por link — compressão gzip nativa (CompressionStream), zero biblioteca
  • Export.ipuz (formato aberto) e .json (wordlist)
  • Progresso salvo — persiste automaticamente a cruzadinha em andamento
  • Bloqueio pós-revelação — ao revelar tudo, o grid fica somente leitura

Pré-requisitos

  • Node.js 18+ (recomendado: 20 LTS)
  • npm 9+
node -v   # ex: v20.11.0
npm -v    # ex: 10.2.4

Instalação

# 1. Clone o repositório
git clone https://github.com/seu-usuario/crossforge.git
cd crossforge

# 2. Instale as dependências
npm install

# 3. Rode o servidor de desenvolvimento
npm run dev

Acesse http://localhost:5173.


Scripts disponíveis

npm run dev         # servidor de desenvolvimento com HMR
npm run build       # build de produção em dist/
npm run preview     # preview do build local
npm run test        # roda os testes unitários uma vez
npm run test:watch  # testes em modo watch
npm run test:coverage  # testes com relatório de cobertura

Estrutura do projeto

crossforge/
├── src/
│   ├── App.jsx              # componente principal e telas (Import / Play)
│   ├── crossword.js         # funções puras: generateLayout, parseInput,
│   │                        # getWordAtCell, exportIpuz
│   └── crossword.test.js    # 42 testes unitários (Vitest)
├── wordlists/               # wordlists temáticas prontas para importar
│   ├── 01_distributed_systems.json
│   ├── 02_kafka_avancado.json
│   ├── 03_jvm_internals.json
│   ├── 04_event_driven_cqrs.json
│   ├── 05_microsservicos.json
│   ├── 06_design_patterns.json
│   ├── 07_observabilidade.json
│   └── 08_concorrencia_java.json
├── .github/
│   └── workflows/
│       └── security.yml     # CI: npm audit, Trivy, license check, testes
├── public/
├── index.html
├── vite.config.js
└── package.json

Formato de entrada

JSON

[
  { "word": "KAFKA",  "clue": "Plataforma de streaming distribuído da Apache" },
  { "word": "BROKER", "clue": "Intermediário que roteia mensagens entre producers e consumers" },
  { "word": "TOPIC",  "clue": "Canal lógico para onde as mensagens são publicadas" }
]

CSV

word,clue
KAFKA,Plataforma de streaming distribuído da Apache
BROKER,Intermediário que roteia mensagens entre producers e consumers
TOPIC,Canal lógico para onde as mensagens são publicadas

Regras:

Regra Detalhe
Caracteres Apenas A–Z, sem espaços ou acentos
Comprimento 2–18 letras (palavras maiores são ignoradas)
Mínimo recomendado 8 palavras para um grid satisfatório
Case Qualquer — normalizado para maiúsculo automaticamente

Compartilhamento por link

O botão ↗ compartilhar gera uma URL com o puzzle encodado:

https://crossforge.app/?p=H4sIAAAAAAAAA...

O payload é comprimido com CompressionStream("gzip") nativo do browser e encodado em base64 URL-safe — zero dependência npm. Quem abre o link começa direto no jogo.


Export: formato IPUZ

O .ipuz é um padrão aberto compatível com vários players e editores:

Player / Editor Suporte
Exet (web)
Phil (web, open source)
Crossword Compiler
Across Lite Parcial (via plugin)
{
  "ipuz": "http://ipuz.org/v1#1",
  "kind": ["http://ipuz.org/crossword#1"],
  "title": "Kafka Fundamentals",
  "dimensions": { "width": 15, "height": 12 },
  "puzzle": [["#", "1", "0", ...], ...],
  "clues": {
    "Across": [[1, "texto da dica"], ...],
    "Down":   [[2, "texto da dica"], ...]
  }
}

Testes

npm run test

42 testes unitários cobrindo as funções puras do módulo crossword.js:

Suite Testes Cobre
parseInput 12 JSON array/objeto, CSV, vírgula na dica, linhas malformadas, erro
generateLayout 14 Casos nulos, normalização, determinismo, grid sem linhas vazias, letras x grid
getWordAtCell 9 Início/meio/fim de palavra, direções, fora do grid
exportIpuz 12 Campos obrigatórios, células #, números, contagem de clues

Thresholds de cobertura (configurados em vite.config.js):

lines: 80% · functions: 90% · branches: 75%

CI/CD (GitHub Actions)

O workflow .github/workflows/security.yml roda automaticamente:

Job Trigger O que faz
npm-audit push / PR Falha em CVEs high ou critical
license-check push / PR Bloqueia GPL/LGPL/AGPL em deps de produção
trivy-scan push / PR Scan do filesystem, sobe resultado ao Security tab
unit-tests push / PR Roda Vitest com cobertura
dependency-updates toda segunda 08h Abre/atualiza issue com deps desatualizadas

Docker

Desenvolvimento (com HMR)

docker compose --profile dev up

Acesse http://localhost:5173. O volume monta o código local no container — edições refletem em tempo real.

Produção (build + nginx)

docker compose --profile prod up --build

Acesse http://localhost:8080. Serve o build otimizado via nginx com cache de assets e fallback de SPA (necessário para links compartilhados com ?p=).

Comandos úteis

# Rebuild sem cache
docker compose --profile prod build --no-cache

# Rodar testes dentro do container
docker compose --profile dev run --rm app-dev npm run test

# Ver logs
docker compose --profile prod logs -f

Deploy estático

O build gera uma pasta dist/ que pode ser servida por qualquer CDN:

npm run build

GitHub Pages:

npm install --save-dev gh-pages

# package.json → adicione:
# "homepage": "https://seu-usuario.github.io/crossforge"
# "scripts": { "deploy": "gh-pages -d dist" }

npm run build && npm run deploy

Também funciona com Vercel, Netlify e Cloudflare Pages sem configuração adicional.


Wordlists temáticas incluídas

15 pares palavra → dica por tema, focados em senioridade backend/arquitetura:

# Tema Destaques
01 Distributed Systems CAP, RAFT, PAXOS, QUORUM, BYZANTINE
02 Kafka Avançado COMPACTION, EXACTLY-ONCE, KTABLE, SCHEMA REGISTRY
03 JVM Internals ZGC, SHENANDOAH, SAFEPOINT, ESCAPE ANALYSIS
04 Event-Driven / CQRS EVENTSOURCING, OUTBOX, SAGA, PROJECTION
05 Microsserviços SIDECAR, CIRCUITBREAKER, STRANGLER, SERVICEMESH
06 Design Patterns GoF Todos os 23 padrões com dicas em PT-BR
07 Observabilidade OPENTELEMETRY, SPAN, EXEMPLAR, CARDINALITY
08 Concorrência Java VIRTUAL THREADS, STRUCTURED CONCURRENCY, CAS

Roadmap

  • Suporte a acentos e ç (normalização automática)
  • AI Theme Wizard — informar tema, IA gera os pares
  • Export para PDF imprimível
  • Modo estudo — ao errar, exibe a dica expandida
  • Timer e pontuação
  • Temas visuais (light mode, alto contraste)
  • Suporte ao formato .puz (Across Lite)
  • Multiplayer / backend opcional

Deploy no GitHub Pages

1. Habilitar Pages no repositório

Settings → Pages → Source → GitHub Actions

2. Ajustar o base path

No workflow .github/workflows/deploy.yml, ajuste a variável conforme seu caso:

VITE_BASE_URL: /crossforge/   # se o repo se chama crossforge
VITE_BASE_URL: /              # se usar domínio customizado

3. Push para main

git push origin main

O pipeline roda automaticamente:

quality-gate (testes + audit)
    ↓
build (npm run build + upload artifact)
    ↓
deploy-pages (GitHub Pages)
    ↓ (paralelo, se DOCKER_ENABLED=true)
docker (build + push para Docker Hub)

Secrets necessários para Docker Hub (opcional)

Em Settings → Secrets and variables → Actions:

Secret Valor
DOCKERHUB_USERNAME seu usuário no Docker Hub
DOCKERHUB_TOKEN Access Token (não a senha)

E em Settings → Variables:

Variable Valor
DOCKER_ENABLED true

Contribuindo

  1. Fork o repositório
  2. Crie uma branch: git checkout -b feat/minha-feature
  3. Rode os testes: npm run test
  4. Abra um PR — o CI verifica segurança, licenças e testes automaticamente

Licença

MIT — use, fork, contribua.

About

Sistema de cruzadinhas temáticas, open source e 100% client-side. Importe um JSON ou CSV com pares `palavra → dica`, gere um grid interativo e jogue no browser — sem backend, sem dependências externas além do React.

Resources

License

Stars

Watchers

Forks

Contributors