Tinder Development Notes: Advancing with Imagination, Exploring the Unknown
If you've been following my GitHub account (well, I bet you haven't, but feel free to connect), you might have noticed that I've been actively opening PRs and releasing updates for a particular project over the past few days. It's this one (by the way, would you mind giving it a star?):
https://github.com/jsshmzx/Tinder
Let me briefly introduce the project: it's an interconnected platform for our maritime community (part of the Voyager Project, set to launch officially in June this year, with an estimated development cycle of one year and public testing next year). Tinder serves as the backend for this platform, built using FastAPI, PostgreSQL, and Redis.
Imagination
Although my senior year studies are quite demanding, I've still managed to carve out time to brainstorm ideas, such as the following (database architecture design diagram, API directory design diagram):
As you can see, if you simply sketch out the blueprint, the entire system seems fairly straightforward. But once you start implementing it, you'll quickly realize—wow, I'm actually not that skilled (yes, I admit it, I'm not very good).
Progress
One development philosophy I always adhere to is: the backend comes first, followed by the frontend. The backend revolves around data, while the frontend focuses on user experience.
So the first step is to tackle the backend and data parts!
Database Migration
Before developing Tinder, I had very limited experience with FastAPI development. Setting up a basic framework (importing the app, configuring CORS, starting the application) wasn't a problem, but what comes next? Honestly, I felt like I was starting from scratch. I welcome feedback from experienced developers on areas for improvement and potential issues.
Since Tinder is developed in Python, I couldn't directly use Prisma for data migration and operations. But hey, that's not a big deal, right? Tinder's data migration approach is inspired by the migration method used in Mix-Space (iterating through existing records, checking for corresponding records in MongoDB, executing relevant files if none are found, and then writing records to the database to prevent repeated execution later). Tinder adopts a similar approach but adapts it to Python + PostgreSQL.
You can use Excalidraw to get a rough understanding of the entire process—it should be pretty straightforward:
Custom Log Printing
This is a feature with limited utility—it's not particularly meaningful. It's mainly intended to replace the default print() function, beautify log output, and make it easier to locate error logs.
Here's the code:
# ANSI color codes
_GREEN = "\033[92m"
_ORANGE = "\033[38;5;208m"
_RED = "\033[91m"
_RESET = "\033[0m"
_LEVEL_CONFIG = {
"SUCCESS": (_GREEN, "[SUCCESS]"),
"WARNING": (_ORANGE, "[WARNING]"),
"ERROR": (_RED, "[ERROR]"),
}
def custom_log(log_level: str, log_content: str) -> None:
"""Print custom colored logs.
Args:
log_level: Log level, supports 'SUCCESS', 'WARNING', 'ERROR' (case-insensitive).
log_content: Log content.
"""
level_key = log_level.upper()
color, label = _LEVEL_CONFIG.get(level_key, (_RESET, f"[{level_key}]"))
print(f"{color} {label} {log_content}{_RESET}")
The Unknown
This has been my biggest takeaway from a few days of development: I'm a newbie and don't know much. After all, this is my first time writing a relatively large-scale API, so I rely heavily on asking AI for help and delegating tasks to agents.
Directory Structure
This might seem like a small detail, but it's worth refining to lay a solid foundation for future development.
Here's the current directory structure. The other day, I asked ds a lot of questions, like whether the database connector counts as a helper or where the firewall should go. After several iterations, I ended up with this relatively clear architecture:
Tinder/
├── .github/ # GitHub configuration directory
│ └── workflows/ # GitHub Actions workflows
│ ├── codeql.yml # CodeQL security scanning workflow
│ ├── docker-build.yml # Docker image build workflow
│ └── test.yml # Automated testing workflow
├── core/ # Core functionality modules
│ ├── database/ # Database-related
│ │ ├── connection/ # Database connection management
│ │ │ ├── db.py # SQLAlchemy engine and session factory (ORM base class Base)
│ │ │ └── redis.py # Redis connection management
│ │ ├── dao/ # Data Access Objects (DAO)
│ │ │ ├── base.py # BaseDAO class providing common CRUD operations
│ │ │ ├── comments.py # ORM model and DAO for comments table
│ │ │ ├── favourites.py # ORM model and DAO for favourites table
│ │ │ ├── illegal_requests.py # ORM model and DAO for illegal requests table
│ │ │ ├── personal_logs.py # ORM model and DAO for personal logs table
│ │ │ ├── relations.py # ORM model and DAO for user relations table
│ │ │ ├── request_logs.py # ORM model and DAO for request logs table
│ │ │ ├── song_arrangements.py # ORM model and DAO for song arrangements table
│ │ │ ├── songs.py # ORM model and DAO for songs table
│ │ │ ├── stores_and_restaurants.py # ORM model and DAO for stores and restaurants table
│ │ │ ├── system_logs.py # ORM model and DAO for system logs table
│ │ │ ├── system_reports.py # ORM model and DAO for system reports table
│ │ │ ├── tags.py # ORM model and DAO for tags table
│ │ │ ├── tasks.py # ORM model and DAO for tasks table
│ │ │ ├── tokens.py # ORM model and DAO for tokens table
│ │ │ ├── users.py # ORM model and DAO for users table
│ │ │ ├── vote.py # ORM model and DAO for votes table
│ │ │ ├── wall_looking_for.py # ORM model and DAO for wall looking-for posts table
│ │ │ └── wall_sayings.py # ORM model and DAO for wall sayings posts table
│ │ └── migrations/ # Database migration management
│ │ ├── SQL/ # Directory for SQL migration scripts
│ │ │ ├── alter_users_add_password.sql # Add password field to users table
│ │ │ ├── initial_comments.sql # Initialize comments table
│ │ │ ├── initial_favourites.sql # Initialize favourites table
│ │ │ ├── initial_illegal_requests.sql # Initialize illegal requests table
│ │ │ ├── initial_migration_user.sql # Initialize users table
│ │ │ ├── initial_personal_logs.sql # Initialize personal logs table
│ │ │ ├── initial_relations.sql # Initialize user relations table
│ │ │ ├── initial_request_logs.sql # Initialize request logs table
│ │ │ ├── initial_song_arrangements.sql # Initialize song arrangements table
│ │ │ ├── initial_songs.sql # Initialize songs table
│ │ │ ├── initial_stores_and_restaurants.sql # Initialize stores and restaurants table
│ │ │ ├── initial_system_logs.sql # Initialize system logs table
│ │ │ ├── initial_system_reports.sql # Initialize system reports table
│ │ │ ├── initial_tags.sql # Initialize tags table
│ │ │ ├── initial_tasks.sql # Initialize tasks table
│ │ │ ├── initial_tokens.sql # Initialize tokens table
│ │ │ ├── initial_vote.sql # Initialize votes table
│ │ │ ├── initial_wall_looking_for.sql # Initialize wall looking-for posts table
│ │ │ └── initial_wall_sayings.sql # Initialize wall sayings posts table
│ │ └── migration_history.py # List of migration script execution order
│ ├── helper/ # General utility tools
│ │ └── ContainerCustomLog/ # Custom log module
│ │ └── index.py # Console log tool with color and timestamps
│ └── middleware/ # Middleware
│ └── firewall/ # Firewall/access control middleware
│ ├── config.py # Firewall rule configuration
│ ├── helpers.py # Firewall helper functions
│ ├── index.py # Exposes FirewallMiddleware
│ └── middleware.py # Firewall middleware implementation (IP blocking, rate limiting, etc.)
├── docs/ # Project documentation
│ └── database/ # Database-related documentation
│ ├── db-migration.excalidraw # Database migration flowchart (Excalidraw format)
│ └── readme.md # Database documentation
├── modules/ # Business functionality modules
│ └── index/ # Root routing module
│ └── index.py # Root route (GET /), returns system information
├── tests/ # Test directory
│ ├── integration/ # Integration tests
│ │ ├── conftest.py # pytest integration test fixtures
│ │ ├── test_api.py # API integration tests
│ │ └── test_firewall.py # Firewall middleware integration tests
│ └── unit/ # Unit tests
│ ├── test_custom_log.py # Unit tests for custom log module
│ ├── test_firewall_helpers.py # Unit tests for firewall helper functions
│ └── test_index_router.py # Unit tests for root route
├── .env.example # Example environment variable file (template for database/Redis configuration)
├── .gitignore # Git ignore rules
├── Dockerfile # Docker image build file
├── LICENSE # Open-source license
├── README.md # Project documentation (this file)
├── db_migrate.py # Database migration entry script (uses psycopg2 to execute SQL)
├── docker-entrypoint.sh # Docker container startup script
├── pytest.ini # pytest configuration file
├── requirements.txt # Python dependency list
└── server.py # FastAPI application entry point, configures middleware and routes
Data Layer
ORM
ORM is something I've often seen in various projects. It primarily ensures security and prevents SQL injection (in one of my previous projects, I even manually concatenated SQL commands—thinking back, it was a bit scary). However, I'm not very familiar with ORM, so I let AI handle it.
DAO and DTO
I first came across DTO in the source code of Mx-Space, though I didn't delve into it at the time.
DAO, on the other hand, I learned about during conversations with ds.
So what's the difference between the two?
DAO (Data Access Object) is responsible for encapsulating database operations like create, read, update, and delete, focusing on "how to store" data. DTO (Data Transfer Object) is a simple container used to encapsulate data for transmission, focusing on "how to transfer" data.
To be honest, before starting development, I had planned to directly call the database in some API files. But as development became more formal, I ended up learning something new.
Controller and Helper
These two concepts were also somewhat vague to me before, but now I have a better understanding. It's like the relationship between a restaurant's manager on duty and the service staff—the latter is merely a resource called upon by the former.
Development Standards
It's hilarious that I, working solo, need to consult AI-written "Database Usage Guidelines." Well, I admit I'm a newbie and still have a lot to learn.
Setting Up the Testing System
I didn't want to write it myself, so I let AI handle it. In the future, any files requiring tests will also be handed over to AI.
Conclusion
Currently, Tinder has been updated to V0.2.3, but most of the implemented parts are auxiliary features. Aside from /, the API section hasn't been developed yet. There's still a long way to go.
The next commit will likely be after the college entrance exam.
105 days left until the exam—wishing for smooth sailing ahead.