Diretório de meetups, talks e eventos de tecnologia por todo Portugal. Curado pelos próprios organizadores das comunidades.
| Camada | Tecnologia |
|---|---|
| Frontend | React 19, TypeScript, Tailwind CSS v4, Vite 7 |
| Backend | Express 5, Node.js (tsx) |
| Base de dados | Notion (via @notionhq/client) |
| Resend | |
| Package manager | pnpm |
# instalar dependências
pnpm install
# copiar variáveis de ambiente
cp .env.example .env.local
# editar .env.local com os valores reais
# iniciar API + frontend em simultâneo
pnpm devO frontend fica em http://localhost:5173 e o API em http://localhost:3001. O Vite faz proxy de /api/* para a porta 3001, por isso não há problemas de CORS em desenvolvimento.
| Variável | Obrigatória | Descrição |
|---|---|---|
NOTION_TOKEN |
✅ | Token de integração Notion (secret_…) |
NOTION_EVENTS_DB |
ID da base de dados de eventos (default já configurado) | |
NOTION_COMMUNITIES_DB |
ID da base de dados de comunidades (default já configurado) | |
ADMIN_PASSWORD |
Password do painel admin (default: ptcadmin) |
|
SESSION_SECRET |
✅ em produção | Segredo HMAC para assinar cookies de sessão |
API_PORT |
Porta do servidor API (default: 3001) |
|
RESEND_API_KEY |
API key Resend (necessária para magic links do portal) | |
RESEND_FROM |
Endereço de remetente (default: noreply@ptc.pt) |
|
SITE_URL |
URL público do site (default: http://localhost:5173) |
ptc-site/
├── server/
│ ├── index.ts # Entrada Express
│ ├── notion.ts # Cliente Notion, parsers, queries
│ ├── lib/
│ │ ├── email.ts # Envio de magic links via Resend
│ │ └── tokens.ts # Geração/consumo de tokens HMAC one-time
│ └── routes/
│ ├── auth.ts # Login/logout/session do admin
│ ├── events.ts # CRUD de eventos
│ ├── communities.ts # Listagem de comunidades
│ ├── config.ts # Configurações do site
│ └── portal.ts # Portal de líderes (magic link auth)
├── src/
│ ├── App.tsx # Router SPA (hash-based)
│ ├── pages/
│ │ ├── Home.tsx # Landing page
│ │ ├── Events.tsx # Lista de eventos
│ │ ├── Communities.tsx # Diretório de comunidades
│ │ ├── CommunityDetail.tsx
│ │ ├── About.tsx
│ │ ├── Admin.tsx # Painel de administração
│ │ └── Portal.tsx # Portal de líderes de comunidade
│ ├── components/ # Componentes reutilizáveis
│ └── lib/
│ ├── api.ts # Funções fetch para o backend
│ ├── siteConfig.ts # Config do site (localStorage + API)
│ └── tokens.ts # Utilitários de token (client-side)
└── vite.config.ts # Proxy /api → 3001
| Método | Path | Auth | Descrição |
|---|---|---|---|
POST |
/login |
— | Login com password; devolve cookie ptc_session |
POST |
/logout |
— | Apaga cookie de sessão |
GET |
/session |
— | Verifica se a sessão está ativa |
| Método | Path | Auth | Descrição |
|---|---|---|---|
GET |
/ |
— | Lista eventos aprovados e futuros (?all=true inclui não aprovados, ?past=true inclui passados) |
GET |
/:id |
— | Evento por ID |
POST |
/ |
Admin ou Portal | Criar evento |
PUT |
/:id |
Admin ou Portal | Editar evento (portal só pode editar os seus) |
DELETE |
/:id |
Admin ou Portal | Arquivar evento |
| Método | Path | Auth | Descrição |
|---|---|---|---|
GET |
/ |
— | Lista comunidades aprovadas |
| Método | Path | Auth | Descrição |
|---|---|---|---|
POST |
/magic-link |
Admin | Envia magic link para líder de comunidade |
GET |
/auth/:token |
— | Valida token e redireciona para /#portal |
GET |
/session |
— | Info da sessão portal atual |
POST |
/logout |
— | Termina sessão portal |
Password simples via ADMIN_PASSWORD. A sessão é um cookie ptc_session assinado com HMAC-SHA256. Válido 8 horas.
⚠️ TODO: Implementar Google OAuth antes de expor o painel publicamente — ver [memory/project_google_oauth_pending.md].
Magic link enviado por email. O admin vai a Admin → Portal e insere o email do líder. O sistema:
- Valida que o email existe na base Notion
CommunityLeaders - Gera token one-time (válido 24h, uso único)
- Envia email via Resend com link
GET /api/portal/auth/:token - Ao clicar, o servidor valida o token, cria cookie
ptc_portalassinado, e redireciona para/#portal
As bases já estão pré-configuradas. Os IDs default estão em server/notion.ts:
pnpm build # compila frontend para dist/
node server/index # serve o API (necessita transpilação prévia)Em produção, servir os ficheiros estáticos de
dist/com um servidor web (nginx, Caddy) e apontar/api/*para o processo Node.
pnpm dev # API + frontend em desenvolvimento
pnpm dev:vite # só frontend
pnpm dev:api # só API
pnpm build # build produção
pnpm typecheck # verificar tipos TypeScript