- 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
8.3 KiB
8.3 KiB
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
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
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
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
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
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
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
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:
{
"username": "daniel",
"email": "daniel@example.com",
"password": "mipass123"
}
Login Response:
{
"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:
{
"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
- Usuario puede registrarse con username, email, password
- Usuario puede hacer login y recibe JWT
- Rutas protegidas requieren token válido
- No permite registro con username/email duplicado
Posts
- Usuario puede crear post con imagen y caption
- Feed global muestra todos los posts ordenados por fecha
- Feed personalizado solo muestra posts de usuarios seguidos
- Usuario puede eliminar SUS propios posts
Likes / Dislikes
- Usuario puede dar like a un post
- Usuario puede dar dislike a un post
- Like y dislike son mutuamente excluyentes
- Contador de likes/dislikes se actualiza en tiempo real
Comentarios
- Usuario puede comentar en un post
- Usuario puede eliminar SUS comentarios
- Lista de comentarios incluye username y timestamp
Follow
- Usuario puede seguir a otro usuario
- Usuario puede dejar de seguir
- No puede followearse a sí mismo
- Stats muestran followers y following count
8. Roadmap de Tasks (para Task Manager)
- Architecture: Crear SPEC.md y estructura del proyecto ✓
- Backlog:
- Setup proyecto FastAPI con SQLite
- Implementar auth (register, login, JWT)
- CRUD posts con upload de imágenes
- Sistema de likes/dislikes
- Sistema de comentarios
- Sistema de follow/unfollow
- Feed global y personalizado
- 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