The project is structured around object-oriented design principles, separating concerns into three distinct layers: the Flask web layer (Documentation Index
Fetch the complete documentation index at: https://mintlify.com/Navi-27/Proyecto-UPC/llms.txt
Use this file to discover all available pages before exploring further.
application.py), the data models (models/), and the external service client (services/). This separation keeps routing logic, domain objects, and third-party API communication cleanly independent, making each layer easy to understand, test, and extend.
Directory Tree
Layer Descriptions
Web Layer — application.py
application.py is the entry point for the entire application. It creates the Flask app instance, sets the session secret key, and initializes the database schema on startup using init_db() inside an app_context() block. All nine routes are registered here:
| Route | Method(s) | Description |
|---|---|---|
/ | GET | Main Pokédex listing with optional tipo and busqueda query parameters |
/pokemon/<nombre> | GET | Individual Pokémon detail; records view if user is logged in |
/mi-pokedex | GET | Authenticated user’s viewed Pokémon history |
/registro | GET, POST | New user registration form and handler |
/login | GET, POST | User login form and handler |
/logout | GET | Clears the session and redirects to index |
/equipo | GET | Authenticated user’s team page |
/equipo/agregar/<pokemon_id>/... | GET | Adds a Pokémon to the user’s team |
/equipo/eliminar/<pokemon_id> | GET | Removes a Pokémon from the user’s team |
parse_tipos Jinja2 template filter, which deserializes the JSON-encoded tipos strings stored in SQLite into Python lists so they render correctly in templates. It tries json.loads first, falling back to ast.literal_eval for robustness.
Model Layer — models/
Each class in models/ is responsible for a specific domain object. The layer is deliberately self-contained — models do not know about Flask or HTTP:
database.py— Providesget_connection()(returns asqlite3.Row-factored connection) andinit_db()(creates all four tables viaexecutescriptif they do not exist). Every model that needs database access importsget_connectionfrom here and opens/closes its own connection per operation.pokemon.py— A pure data class. Holds all fields for a single Pokémon (id, name, types, height, weight, sprite URL, base stats). Contains no database logic.pokedex.py— A collection class that wraps a list ofPokemonobjects. Provides search, filtering, and bulk persistence methods.usuario.py— Handles user creation and authentication using Werkzeug password hashing. Exposes only static methods.equipo.py— Manages a per-user team of up to six Pokémon. Enforces theMAX_POKEMONES = 6constraint and uniqueness in static methods.pokedex_usuario.py— Tracks which Pokémon a given user has viewed, with a timestamp. Also uses static methods exclusively.
Service Layer — services/
services/poke_api.py contains the PokeAPI class, the only component that communicates with the external PokéAPI REST API. It abstracts all HTTP request logic behind clean Python methods and implements a cache-first strategy: on startup the application checks whether the local cache_pokemon SQLite table is already populated, and only hits the network if the cache is empty. Subsequent calls for individual Pokémon also query the cache before making an outbound request.
OOP Design Principles
The Pokédex Web App demonstrates three foundational object-oriented principles in practice:- Encapsulation — Each class bundles its data and the operations on that data together.
Pokemonowns its attributes;Equipoowns the rules for team membership;PokeAPIowns the HTTP and caching logic. - Abstraction —
PokeAPIhides all network and SQLite details behind descriptive method names. Routes inapplication.pycallapi.obtener_pokemon("pikachu")without knowing anything about HTTP, JSON parsing, or cache lookups. - Separation of concerns — Flask routes handle user input and template rendering only. Models handle data persistence. The service layer handles external I/O. No layer reaches into another’s responsibility.