Skip to content

Commit 7ef214b

Browse files
lpirolaclaude
andcommitted
docs(activitypub): adiciona README com endpoints, configuração e limitações
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 772d17d commit 7ef214b

1 file changed

Lines changed: 137 additions & 0 deletions

File tree

src/plugins/ActivityPub/README.md

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
# Plugin ActivityPub
2+
3+
Expõe cada **Agente** do Mapas Culturais como um **Actor ActivityPub**, permitindo que instâncias do Fediverso (Mastodon, Pleroma, Misskey etc.) descubram e sigam agentes culturais via protocolo W3C ActivityPub.
4+
5+
## Como funciona
6+
7+
### Descoberta via WebFinger
8+
9+
O Fediverso descobre atores pelo protocolo [WebFinger (RFC 7033)](https://www.rfc-editor.org/rfc/rfc7033). Para buscar um agente chamado **Admin**:
10+
11+
```
12+
GET /.well-known/webfinger?resource=acct:admin@seu.dominio
13+
```
14+
15+
Resposta:
16+
```json
17+
{
18+
"subject": "acct:admin@seu.dominio",
19+
"links": [{
20+
"rel": "self",
21+
"type": "application/activity+json",
22+
"href": "https://seu.dominio/activitypub/agent/admin"
23+
}]
24+
}
25+
```
26+
27+
O username (`admin`) é gerado automaticamente a partir do nome do agente via slugify — acentos são transliterados, espaços viram hífens.
28+
29+
### Perfil do Actor (Person)
30+
31+
```
32+
GET /activitypub/agent/{slug}
33+
Accept: application/activity+json
34+
```
35+
36+
Retorna um objeto `Person` com:
37+
- `id`, `preferredUsername`, `name`, `summary`, `url`
38+
- `inbox` e `outbox`
39+
- `publicKey` (stub vazio — assinatura HTTP não implementada ainda)
40+
- `icon` (avatar do agente, se disponível)
41+
42+
### Outbox paginada
43+
44+
```
45+
GET /activitypub/agent/{slug}/outbox # coleção total
46+
GET /activitypub/agent/{slug}/outbox?page=1 # primeira página (20 itens)
47+
```
48+
49+
Retorna `OrderedCollection` / `OrderedCollectionPage` com as atividades registradas do agente. As atividades são gravadas na tabela `activitypub_activity` via job assíncrono quando o agente salva eventos, espaços, projetos, oportunidades ou inscrições.
50+
51+
### Atividades suportadas
52+
53+
| Entidade Mapas | Tipo ActivityPub | Disparado em |
54+
|----------------------|------------------|--------------------|
55+
| Event | `Event` | Create / Update |
56+
| Space | `Place` | Create / Update |
57+
| Project | `Note` | Create / Update |
58+
| Opportunity | `Note` | Create / Update |
59+
| Registration | `Note` | Announce |
60+
| AgentRelation | `Relationship` | Add |
61+
62+
## Endpoints
63+
64+
| Método | Rota | Descrição |
65+
|--------|---------------------------------------------------|-------------------------|
66+
| GET | `/.well-known/webfinger?resource=acct:{slug}@{domain}` | Descoberta WebFinger |
67+
| GET | `/activitypub/agent/{slug}` | Perfil Actor (Person) |
68+
| GET | `/activitypub/agent/{slug}/outbox[?page=N]` | Outbox paginada |
69+
| GET | `/activitypub/agent/{slug}/inbox` | Inbox (stub vazio) |
70+
| GET | `/activitypub/agent/{slug}/activities/{hash}` | Atividade individual |
71+
72+
O `{slug}` aceita tanto o nome slugificado (`admin`) quanto o ID numérico do agente (`42`) para compatibilidade.
73+
74+
## Configuração
75+
76+
Em `dev/config.d/0.main.php` (ou equivalente de produção):
77+
78+
```php
79+
'activitypub.enabled' => true,
80+
'activitypub.domain' => '', // deixar vazio para usar o host de base.url
81+
```
82+
83+
Em `dev/config.d/plugins.php`:
84+
85+
```php
86+
'ActivityPub' => ['namespace' => 'ActivityPub'],
87+
```
88+
89+
## Banco de dados
90+
91+
A migration cria a tabela `activitypub_activity` automaticamente na inicialização do container:
92+
93+
```sql
94+
id BIGSERIAL PRIMARY KEY
95+
agent_id INTEGER REFERENCES agent(id) ON DELETE CASCADE
96+
type VARCHAR(50) -- Create, Update, Announce, Add
97+
object_type VARCHAR(100) -- MapasCulturais\Entities\Event etc.
98+
object_id INTEGER
99+
activity_id TEXT UNIQUE -- URI canônica da atividade
100+
payload JSONB -- payload completo ActivityPub
101+
published TIMESTAMPTZ
102+
```
103+
104+
Índices: performance em `(agent_id, published DESC)` e deduplicação parcial em `(agent_id, object_type, object_id) WHERE type = 'Create'`.
105+
106+
## Testando localmente
107+
108+
```bash
109+
# 1. Copiar plugin (container monta do repo principal)
110+
cp -r src/plugins/ActivityPub /var/www/src/plugins/ # ou via bind mount
111+
112+
# 2. Aplicar migration
113+
./scripts/db-update.sh
114+
115+
# 3. Descobrir um agente (substitua "admin" pelo slug do agente)
116+
curl -s "http://localhost:8080/.well-known/webfinger?resource=acct:admin@localhost" | jq .
117+
118+
# 4. Ver perfil Actor
119+
curl -s -H "Accept: application/activity+json" \
120+
"http://localhost:8080/activitypub/agent/admin" | jq .
121+
122+
# 5. Ver outbox
123+
curl -s -H "Accept: application/activity+json" \
124+
"http://localhost:8080/activitypub/agent/admin/outbox" | jq .
125+
```
126+
127+
Para descobrir slugs disponíveis:
128+
```bash
129+
dev/psql.sh -c "SELECT id, name FROM agent WHERE status = 1 LIMIT 10;"
130+
```
131+
132+
## Limitações atuais
133+
134+
- **Sem assinatura HTTP**: o `publicKey.publicKeyPem` é vazio — outros servidores ActivityPub não conseguem verificar requisições de saída. Necessário para follow/unfollow real.
135+
- **Sem Inbox funcional**: requisições recebidas de outros servidores são ignoradas.
136+
- **Slug não único**: dois agentes com o mesmo nome geram o mesmo slug; o primeiro ativo encontrado é retornado.
137+
- **Busca por slug em memória**: `findAgent()` itera todos os agentes ativos. Adequado para instâncias pequenas; instâncias grandes precisarão de coluna `activitypub_username` indexada.

0 commit comments

Comments
 (0)