Skip to content

webarthur/devcam

Repository files navigation

DevCam

Monitoramento de segurança via webcam no browser: seleção de dispositivo, preview A+V, gravação contínua ou por movimento, upload para servidor e acesso remoto (ngrok).

DevCam — interface host

Stack

  • RuntimeBun
  • ServerHono
  • Client — HTML, CSS, vanilla JS (ES modules, sem build)
  • Tunnel — ngrok (HTTPS para acesso mobile)

Features

  • Seleção de câmera (enumerateDevices + getUserMedia)
  • Preview ao vivo (vídeo mudo para evitar feedback)
  • Gravação WebM (áudio + vídeo) via MediaRecorder
  • Modo continuous — grava a sessão inteira enquanto monitoramento ativo
  • Modo motion — grava só com movimento; segmentos enviados após cooldown
  • Upload multipart para recordings/
  • Listagem, playback e download de gravações
  • Streaming ao vivo — host publica JPEG via WebSocket; viewers recebem MJPEG
  • Autenticação por senha (cookie assinado) — desligável com PASSWORD=FALSE

Pré-requisitos

  • Bun instalado
  • Webcam e microfone
  • ngrok (opcional, para acesso fora de localhost — getUserMedia exige HTTPS)

Setup

bun install
cp .env.example .env # editar variáveis
bun run dev

App em http://localhost:3000.

Variáveis de ambiente

Variável Obrigatória Default Descrição
PASSWORD sim* Senha de acesso; FALSE desliga auth
SESSION_SECRET sim** HMAC do cookie de sessão
PORT não 3000 Porta do servidor
RECORDINGS_DIR não ./recordings Pasta das gravações
LOGIN_RATE_MAX não 5 Tentativas de login por janela
LOGIN_RATE_WINDOW_MS não 900000 Janela de rate limit (ms)
MOTION_STOP_DELAY_SEC não 5 Segundos após último movimento (modo motion)

* Exceto quando PASSWORD=FALSE
** Obrigatório quando auth está ativa

Nunca commitar .env nem credenciais ngrok.

Autenticação

Proteção por senha no .env com cookie de sessão assinado (HMAC). Ativa quando PASSWORD está definida e não é FALSE.

Ativar / desativar

# auth ligada (padrão)
PASSWORD=changeme
SESSION_SECRET=random-long-string

# auth desligada — app aberto sem login
PASSWORD=FALSE

Com auth desligada: middleware não monta, SESSION_SECRET dispensável, rotas abertas.

Com auth ligada: servidor não sobe sem PASSWORD e SESSION_SECRET no .env.

Fluxo

  1. Cliente acessa / sem sessão → redirect para /login.html
  2. POST /api/login com { password } — compara com PASSWORD do env
  3. Sucesso → cookie devcam_session (HttpOnly, SameSite=Lax, Secure em HTTPS)
  4. Rotas e assets protegidos liberados; auth.js redireciona em 401
  5. POST /api/logout limpa o cookie

O que fica aberto vs protegido

Aberto (sem sessão) Protegido
/login.html, CSS/JS do login /, /watch.html, demais estáticos
POST /api/login /api/* (exceto login e auth/status)
GET /api/auth/status /recordings/*
WS /api/stream/ws

GET /api/auth/status retorna { authEnabled, authenticated } sem exigir sessão — usado pelo client para decidir redirect.

Rate limit no login

Tentativas com senha errada limitadas por IP (memória):

  • LOGIN_RATE_MAX — máx. tentativas (default 5)
  • LOGIN_RATE_WINDOW_MS — janela em ms (default 900000 = 15 min)
  • Resposta 429 quando excedido

Spec: specs/server/auth.yaml

Scripts

bun run dev      # servidor com hot reload
bun test         # testes
bun run tunnel   # ngrok http 3000

Acesso remoto (ngrok)

O DevCam roda no PC com a webcam. Para ver o monitoramento no celular ou em outra rede, o servidor local precisa ficar acessível via HTTPS — os browsers só liberam getUserMedia (câmera/mic) em contexto seguro (localhost ou HTTPS).

O ngrok cria um túnel HTTPS público até o localhost:3000, sem configurar roteador, certificado ou DNS.

Host vs viewer

Papel Onde abrir O que faz
Host http://localhost:3000 (máquina com webcam) Seleciona câmera, grava, publica stream ao vivo
Viewer URL HTTPS do ngrok (celular, outro PC) Vê MJPEG ao vivo, lista e baixa gravações — sem acesso à câmera local

Detecção automática em role.js: localhost / 127.0.0.1 / 192.168.x.x = host; qualquer outro hostname (ex. *.ngrok-free.app) = viewer.

Passos

  1. Na máquina com webcam: bun run dev
  2. No mesmo host: bun run tunnel (requer ngrok instalado e autenticado)
  3. Abrir http://localhost:3000 — iniciar monitoramento (host)
  4. No celular: abrir a URL HTTPS exibida pelo ngrok — modo viewer

Observações

  • Plano free do ngrok: URL muda a cada sessão
  • Com auth ativa: login na URL ngrok; cookie Secure em HTTPS (localhost HTTP segue sem Secure)
  • iOS: <video playsinline> já configurado no host
  • Gravações continuam no servidor local (recordings/), não no celular

Estrutura

src/           # Hono — rotas, handlers, middleware, lib
public/        # HTML, CSS, JS (servido em /)
recordings/    # gravações recebidas (gitignored)
scripts/       # utilitários (tunnel, cleanup)
specs/         # contratos YAML (fonte de verdade)
tests/         # testes Bun

API (resumo)

Método Rota Descrição
POST /api/login Autenticação
POST /api/logout Encerra sessão
GET /api/auth/status Estado de auth
GET /api/config Config client-side
POST /api/recordings Upload WebM
GET /api/recordings Lista gravações
GET /recordings/:name Playback/download
GET /api/health Liveness
WS /api/stream/ws Host publica frames
GET /api/stream MJPEG para viewers
GET /api/stream/status Status do stream

Cultura de desenvolvimento

Este repo é intencionalmente pequeno e legível. Não é um showcase de framework — é um app que resolve um problema com o mínimo de moving parts.

Princípios

  • Simples — Bun + Hono no server; HTML/CSS/vanilla JS no client; sem bundler, sem React, sem ORM
  • Limites claros — um arquivo, uma responsabilidade; funções puras; sem classes
  • Escopo mínimo — mudança só no que o pedido pede; copiar o vizinho em vez de inventar camada
  • Manutenção > esperteza — código que um dev experiente lê em cinco minutos

Pré-raciocínio

Antes de planejar ou codificar — humano ou agente — a primeira ação é ler o contrato, não inferir do código legado:

  1. Identificar escopo: project, server, frontend, recording, streaming ou tunnel
  2. Consultar o mapa de specs (abaixo) e specs/conventions/
  3. Usar o contrato lido como base — spec-as-source: specs/ é a fonte de verdade; o spec-driven development (SDD) define o que implementar

Sem spec no escopo (infra nova): fase intent (conversa no chat) → draft na spec → código.

Vibe-spec

As specs deste repo nasceram em vibe-spec — o mesmo espírito do vibe coding, mas o artefato é YAML em specs/, não código solto. Conversa iterativa com IA vira contrato versionável; não é documentação escrita depois do fato sobre código legado.

Os nomes das propriedades nos YAML foram escolhidos pelo modelo usado no vibe-spec, não há schema imposto nem convenção externa; o que importa é o contrato semântico, não o vocabulário das chaves.

Spec-first (SDD)

Contratos em specs/ são a fonte de verdade para infraestrutura. O código implementa a spec; a spec não documenta o código depois.

intent → spec → plan → code → review
Etapa O quê
intent conversa com o chat via prompt — alinhar escopo e intenção antes de escrever YAML
spec YAML por domínio (server, frontend, recording, streaming)
plan planejamento multi-arquivo no editor — não versionado
code implementação alinhada ao contrato
review conferir spec ↔ código antes de fechar

A etapa intent não vira arquivo no repo; o rastro opcional na spec é o campo intention (trecho do prompt que originou o contrato).

Regras:

  • PR só de spec → não mexe em código
  • PR de implementação → spec existe ou é atualizada antes do código no mesmo PR
  • Bug: corrige código se a spec está certa; ou altera a spec primeiro se o contrato mudou
  • Sem validador automático das specs — consistência por leitura humana e cross-refs

Não inferir comportamento de código legado quando há spec. Spec ausente em infra nova → draft na spec, depois código.

Mapa de specs

Caminho Conteúdo
specs/project/project.spec.yaml projeto, features, env
specs/server/architecture.yaml rotas, handlers, storage
specs/server/auth.yaml autenticação
specs/frontend/architecture.yaml UI, módulos client, fluxos
specs/frontend/modules/*.module.yaml contrato por módulo JS
specs/recording/*.recording.yaml modos continuous, motion, upload, playback
specs/streaming/*.stream.yaml host WebSocket, viewer MJPEG
specs/conventions/*.spec.md como escrever specs por domínio

Specs de feature (*.recording.yaml, *.module.yaml) têm status: draftreviewstable. Campo opcional intention guarda o trecho do prompt da fase intent.

AGENTS.md — guia operacional para coding agents. Não repete produto/setup (README) nem contratos de comportamento (specs/).

Por que o AGENTS.md é extenso

Agentes de IA não têm memória persistente entre sessões. Cada conversa começa sem contexto do repo — só o que entra no prompt (arquivos abertos, regras do workspace, AGENTS.md). O arquivo é grande porque concentra o que um dev experiente já sabe depois de semanas no projeto, mas o agente precisa ler em segundos:

  • Onde olhar — mapa de specs e mapa do repo (qual arquivo tocar por domínio)
  • Em que ordem — pré-raciocínio: spec antes de código; intent → spec → code → review
  • Como se comportar — escopo mínimo, copiar o vizinho, não commitar sem pedido, bun test antes de encerrar
  • Como escrever — persona, estilo (sem ;, funções puras, sem OOP novo)

Detalhe aqui não é documentação retroativa do código — é guardrail operacional. O contrato técnico continua em specs/; o README continua produto e setup.

Impacto na qualidade e na “consciência” do agente

Sem AGENTS.md detalhado Com AGENTS.md detalhado
Infere comportamento do código legado Lê spec como fonte de verdade
Refactor e abstração fora do escopo Diff pequeno, só o pedido
Toca arquivos errados ou inventa camada Mapa do repo aponta o vizinho certo
Spec e código divergem Spec atualizada antes do código
Estilo inconsistente entre sessões Mesma persona e convenções a cada run

Consciência do agente = saber onde está no projeto (domínio, arquivos, fluxo SDD) antes de agir — não “inteligência” extra, mas contexto explícito que reduz alucinação de arquitetura e decisões fora de contrato. Quanto mais o AGENTS.md deixa o caminho óbvio, menos o agente improvisa e mais o output se parece com contribuição de alguém que já leu o repo.

Desenvolvimento com IA

Parte do código e das specs foi escrita com assistência do Cursor Composer 2.5 em fluxo vibe-spec: intent no chat → contrato em specs/ → diff pequeno → review spec ↔ implementação. O SDD existe para que vibe coding não vire pasta de código órfão.

Para quem vai julgar no GitHub

Pode criticar à vontade. Antes de abrir issue sobre “falta X”: confira se specs/ já define o comportamento esperado. Se a spec estiver errada, o bug é de contrato; se o código divergir, o bug é de implementação.

Tradeoffs conscientes:

  • Sem bundler — deploy = copiar public/; DX moderna sacrificada por simplicidade
  • YAML sem schema CI — leve, versionável, legível; validação manual
  • Auth por senha única no .env — adequado a uso pessoal/local, não multi-tenant
  • Rate limit em memória — reinicia com o processo

Issues e PRs bem fundamentados são bem-vindos.

Licença

MIT

About

Monitoramento de segurança via webcam no browser: seleção de dispositivo, preview A+V, gravação contínua ou por movimento, upload para servidor e acesso remoto (ngrok).

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors