# 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: ``` **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 ` ### 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