- FastAPI backend with SQLite database - JWT authentication (register, login) - User profiles with follow/unfollow - Posts with image upload and likes/dislikes - Comments with likes - Global and personalized feed - Comprehensive pytest test suite (37 tests) TASK-ID: 758f4029-702
338 lines
8.3 KiB
Markdown
338 lines
8.3 KiB
Markdown
# SPEC.md — Instagram Clone (SocialPhoto)
|
|
|
|
> Sistema de red social para compartir imágenes con likes, comentarios y seguimiento de usuarios
|
|
|
|
## 1. Concepto & Visión
|
|
|
|
**SocialPhoto** es un clon minimalista de Instagram que prioriza la simplicidad y velocidad. Permite a usuarios registrarse, subir imágenes, interactuar con publicaciones (likes/no me gusta), comentar y seguir a otros usuarios. El enfoque es en ser rápido, portable (todo en un archivo SQLite) y fácil de desplegar.
|
|
|
|
**Principios:**
|
|
- Simple de instalar y operar
|
|
- Base de datos portable (SQLite)
|
|
- API RESTful clara y documentada
|
|
- Ideal para testing de agentes de IA
|
|
|
|
---
|
|
|
|
## 2. Stack Tecnológico
|
|
|
|
| Componente | Tecnología |
|
|
|------------|------------|
|
|
| **Backend** | Python 3.11+ con FastAPI |
|
|
| **Base de datos** | SQLite3 |
|
|
| **Auth** | JWT (python-jose) |
|
|
| **Upload imágenes** | Almacenamiento local en `/uploads` |
|
|
| **Password hashing** | bcrypt |
|
|
| **Testing** | pytest + pytest-asyncio |
|
|
| **CLI (testing)** | curl o httpie |
|
|
|
|
---
|
|
|
|
## 3. Modelo de Datos (SQLite)
|
|
|
|
### Tabla: `users`
|
|
|
|
```sql
|
|
CREATE TABLE users (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
username TEXT UNIQUE NOT NULL,
|
|
email TEXT UNIQUE NOT NULL,
|
|
password_hash TEXT NOT NULL,
|
|
avatar_url TEXT DEFAULT '/static/default-avatar.png',
|
|
bio TEXT DEFAULT '',
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
```
|
|
|
|
### Tabla: `posts`
|
|
|
|
```sql
|
|
CREATE TABLE posts (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
user_id INTEGER NOT NULL REFERENCES users(id),
|
|
image_path TEXT NOT NULL,
|
|
caption TEXT DEFAULT '',
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
```
|
|
|
|
### Tabla: `comments`
|
|
|
|
```sql
|
|
CREATE TABLE comments (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
post_id INTEGER NOT NULL REFERENCES posts(id),
|
|
user_id INTEGER NOT NULL REFERENCES users(id),
|
|
content TEXT NOT NULL,
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
);
|
|
```
|
|
|
|
### Tabla: `likes`
|
|
|
|
```sql
|
|
CREATE TABLE likes (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
post_id INTEGER NOT NULL REFERENCES posts(id),
|
|
user_id INTEGER NOT NULL REFERENCES users(id),
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
UNIQUE(post_id, user_id)
|
|
);
|
|
```
|
|
|
|
### Tabla: `dislikes`
|
|
|
|
```sql
|
|
CREATE TABLE dislikes (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
post_id INTEGER NOT NULL REFERENCES posts(id),
|
|
user_id INTEGER NOT NULL REFERENCES users(id),
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
UNIQUE(post_id, user_id)
|
|
);
|
|
```
|
|
|
|
### Tabla: `follows`
|
|
|
|
```sql
|
|
CREATE TABLE follows (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
follower_id INTEGER NOT NULL REFERENCES users(id),
|
|
following_id INTEGER NOT NULL REFERENCES users(id),
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
UNIQUE(follower_id, following_id)
|
|
);
|
|
```
|
|
|
|
### Tabla: `comment_likes`
|
|
|
|
```sql
|
|
CREATE TABLE comment_likes (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
comment_id INTEGER NOT NULL REFERENCES comments(id),
|
|
user_id INTEGER NOT NULL REFERENCES users(id),
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
UNIQUE(comment_id, user_id)
|
|
);
|
|
```
|
|
|
|
---
|
|
|
|
## 4. API Endpoints
|
|
|
|
### Autenticación
|
|
|
|
| Método | Endpoint | Descripción |
|
|
|--------|----------|-------------|
|
|
| POST | `/auth/register` | Registrar usuario |
|
|
| POST | `/auth/login` | Login, retorna JWT |
|
|
|
|
**Register Request:**
|
|
```json
|
|
{
|
|
"username": "daniel",
|
|
"email": "daniel@example.com",
|
|
"password": "mipass123"
|
|
}
|
|
```
|
|
|
|
**Login Response:**
|
|
```json
|
|
{
|
|
"access_token": "eyJ...",
|
|
"token_type": "bearer"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Usuarios
|
|
|
|
| Método | Endpoint | Descripción |
|
|
|--------|----------|-------------|
|
|
| GET | `/users/{id}` | Obtener perfil de usuario |
|
|
| GET | `/users/{id}/posts` | Posts de un usuario |
|
|
| GET | `/users/{id}/stats` | Stats (posts, followers, following) |
|
|
| POST | `/users/{id}/follow` | Seguir usuario |
|
|
| DELETE | `/users/{id}/follow` | Dejar de seguir |
|
|
|
|
---
|
|
|
|
### Posts
|
|
|
|
| Método | Endpoint | Descripción |
|
|
|--------|----------|-------------|
|
|
| POST | `/posts` | Crear post (con imagen) |
|
|
| GET | `/posts` | Feed global |
|
|
| GET | `/posts/{id}` | Detalle de post |
|
|
| DELETE | `/posts/{id}` | Eliminar post |
|
|
| POST | `/posts/{id}/like` | Dar like |
|
|
| DELETE | `/posts/{id}/like` | Quitar like |
|
|
| POST | `/posts/{id}/dislike` | Dar no me gusta |
|
|
| DELETE | `/posts/{id}/dislike` | Quitar no me gusta |
|
|
|
|
**Crear Post:**
|
|
```
|
|
POST /posts
|
|
Content-Type: multipart/form-data
|
|
|
|
caption: "Mi primera foto"
|
|
image: <archivo>
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"id": 1,
|
|
"user_id": 1,
|
|
"username": "daniel",
|
|
"image_url": "/uploads/abc123.jpg",
|
|
"caption": "Mi primera foto",
|
|
"likes_count": 0,
|
|
"dislikes_count": 0,
|
|
"comments_count": 0,
|
|
"created_at": "2026-04-15T22:00:00Z"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Comentarios
|
|
|
|
| Método | Endpoint | Descripción |
|
|
|--------|----------|-------------|
|
|
| GET | `/posts/{post_id}/comments` | Listar comentarios |
|
|
| POST | `/posts/{post_id}/comments` | Agregar comentario |
|
|
| DELETE | `/comments/{id}` | Eliminar comentario |
|
|
| POST | `/comments/{id}/like` | Dar like a comentario |
|
|
|
|
---
|
|
|
|
### Feed
|
|
|
|
| Método | Endpoint | Descripción |
|
|
|--------|----------|-------------|
|
|
| GET | `/feed` | Feed de usuarios que sigues |
|
|
| GET | `/feed/global` | Feed global (todos) |
|
|
|
|
**Query params:** `?limit=20&offset=0`
|
|
|
|
---
|
|
|
|
## 5. Detalles de Implementación
|
|
|
|
### Upload de Imágenes
|
|
- Directorio: `./uploads/`
|
|
- Nombres: `{uuid}_{original_filename}`
|
|
- Formatos: jpg, jpeg, png, gif, webp
|
|
- Tamaño máximo: 10MB
|
|
|
|
### Auth JWT
|
|
- Algorithm: HS256
|
|
- Expiración: 24 horas
|
|
- Header: `Authorization: Bearer <token>`
|
|
|
|
### Likes/Dislikes
|
|
- Un usuario solo puede dar UN like O un dislike por post (no ambos)
|
|
- Dar dislike si ya hay like lo reemplaza
|
|
- Dar like si ya hay dislike lo reemplaza
|
|
|
|
### Follow
|
|
- No puedes seguirte a ti mismo
|
|
- Mensaje de error si intentas seguir alguien que ya sigues
|
|
|
|
### Timestamps
|
|
- Todos en UTC
|
|
- Formato ISO 8601 en responses
|
|
|
|
---
|
|
|
|
## 6. Estructura del Proyecto
|
|
|
|
```
|
|
socialphoto/
|
|
├── app/
|
|
│ ├── __init__.py
|
|
│ ├── main.py # FastAPI app
|
|
│ ├── database.py # SQLite connection + setup
|
|
│ ├── models.py # Pydantic models
|
|
│ ├── auth.py # JWT auth helpers
|
|
│ ├── routes/
|
|
│ │ ├── __init__.py
|
|
│ │ ├── auth.py
|
|
│ │ ├── users.py
|
|
│ │ ├── posts.py
|
|
│ │ ├── comments.py
|
|
│ │ └── feed.py
|
|
│ └── services/
|
|
│ └── __init__.py
|
|
├── uploads/ # Imágenes
|
|
├── tests/
|
|
│ ├── __init__.py
|
|
│ ├── conftest.py
|
|
│ ├── test_auth.py
|
|
│ ├── test_posts.py
|
|
│ └── test_social.py
|
|
├── requirements.txt
|
|
├── SPEC.md
|
|
└── README.md
|
|
```
|
|
|
|
---
|
|
|
|
## 7. Criterios de Aceptación
|
|
|
|
### Auth
|
|
- [x] Usuario puede registrarse con username, email, password
|
|
- [x] Usuario puede hacer login y recibe JWT
|
|
- [x] Rutas protegidas requieren token válido
|
|
- [x] No permite registro con username/email duplicado
|
|
|
|
### Posts
|
|
- [x] Usuario puede crear post con imagen y caption
|
|
- [x] Feed global muestra todos los posts ordenados por fecha
|
|
- [x] Feed personalizado solo muestra posts de usuarios seguidos
|
|
- [x] Usuario puede eliminar SUS propios posts
|
|
|
|
### Likes / Dislikes
|
|
- [x] Usuario puede dar like a un post
|
|
- [x] Usuario puede dar dislike a un post
|
|
- [x] Like y dislike son mutuamente excluyentes
|
|
- [x] Contador de likes/dislikes se actualiza en tiempo real
|
|
|
|
### Comentarios
|
|
- [x] Usuario puede comentar en un post
|
|
- [x] Usuario puede eliminar SUS comentarios
|
|
- [x] Lista de comentarios incluye username y timestamp
|
|
|
|
### Follow
|
|
- [x] Usuario puede seguir a otro usuario
|
|
- [x] Usuario puede dejar de seguir
|
|
- [x] No puede followearse a sí mismo
|
|
- [x] Stats muestran followers y following count
|
|
|
|
---
|
|
|
|
## 8. Roadmap de Tasks (para Task Manager)
|
|
|
|
1. **Architecture**: Crear SPEC.md y estructura del proyecto ✓
|
|
2. **Backlog**:
|
|
- [x] Setup proyecto FastAPI con SQLite
|
|
- [x] Implementar auth (register, login, JWT)
|
|
- [x] CRUD posts con upload de imágenes
|
|
- [x] Sistema de likes/dislikes
|
|
- [x] Sistema de comentarios
|
|
- [x] Sistema de follow/unfollow
|
|
- [x] Feed global y personalizado
|
|
- [x] Tests unitarios
|
|
- [ ] README y documentación
|
|
|
|
---
|
|
|
|
## 9. Notas
|
|
|
|
- Usar SQLite para simplicidad y portabilidad
|
|
- No requiere Docker ni servicios externos
|
|
- Ideal para testing de SDMAS Orchestrator
|
|
- En producción real se migraría a PostgreSQL
|