637 lines
13 KiB
Markdown
637 lines
13 KiB
Markdown
💍 Wedding Site
|
||
|
||
A personal wedding website with guest authentication, RSVP forms, event information, and an administration panel.
|
||
|
||
⸻
|
||
|
||
📖 About the Project
|
||
|
||
Wedding Site is a web application designed for a wedding event.
|
||
|
||
The website allows guests to:
|
||
|
||
* receive a personalized invitation;
|
||
* authenticate using a unique access code;
|
||
* view the wedding schedule;
|
||
* get information about transportation and travel;
|
||
* browse photos;
|
||
* fill out a guest questionnaire;
|
||
* specify food and drink preferences;
|
||
* leave a personal message or request.
|
||
|
||
The organizers have access to administrative features for managing guests.
|
||
|
||
The project is a full-stack application with a Python backend and a native HTML/CSS/JavaScript frontend.
|
||
|
||
⸻
|
||
|
||
✨ Features
|
||
|
||
👰 For Guests
|
||
|
||
* 🔐 Authentication using a unique 6-digit code
|
||
* 🎫 Personalized access to the invitation
|
||
* 📅 Wedding day schedule
|
||
* 🚗 Transportation and travel information
|
||
* 📸 Photo gallery
|
||
* 📝 Guest questionnaire
|
||
* 🍽️ Food preferences
|
||
* 🥂 Drink preferences
|
||
* 💬 Ability to leave a message or request
|
||
* 🚪 Secure logout
|
||
|
||
👨💼 For Administrators
|
||
|
||
* 👥 View the guest list
|
||
* ➕ Create new guests
|
||
* ✏️ Edit guest information
|
||
* 🔑 Manage guest access codes
|
||
* 📊 View guest activation status
|
||
* 🕐 Track the last login time
|
||
* 🛡️ Role-based administrative access
|
||
|
||
⸻
|
||
|
||
🏗️ Architecture
|
||
|
||
┌─────────────────────┐
|
||
│ Guest │
|
||
│ Browser / Mobile │
|
||
└──────────┬──────────┘
|
||
│
|
||
HTTPS / HTTP
|
||
│
|
||
▼
|
||
┌─────────────────────┐
|
||
│ Caddy │
|
||
│ Reverse Proxy / TLS │
|
||
└──────────┬──────────┘
|
||
│
|
||
▼
|
||
┌─────────────────────┐
|
||
│ FastAPI │
|
||
│ Backend │
|
||
└──────────┬──────────┘
|
||
│
|
||
┌──────────────────┼──────────────────┐
|
||
│ │ │
|
||
▼ ▼ ▼
|
||
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
|
||
│ JWT │ │ Pydantic │ │ SQLAlchemy │
|
||
│ Auth │ │ Validation │ │ ORM │
|
||
└─────────────┘ └─────────────┘ └──────┬──────┘
|
||
│
|
||
▼
|
||
┌─────────────┐
|
||
│ SQLite │
|
||
│ guests.db │
|
||
└─────────────┘
|
||
|
||
⸻
|
||
|
||
🧰 Technologies
|
||
|
||
Backend
|
||
|
||
Technology Purpose
|
||
Python 3.13 Core programming language
|
||
FastAPI REST API
|
||
Uvicorn ASGI server
|
||
Pydantic Data validation
|
||
SQLAlchemy 2 ORM
|
||
SQLite Database
|
||
aiosqlite Async SQLite driver
|
||
Alembic Database migrations
|
||
PyJWT JWT authentication
|
||
|
||
Frontend
|
||
|
||
Technology Purpose
|
||
HTML5 Markup
|
||
CSS3 Styling
|
||
JavaScript Client-side logic
|
||
Swiper.js Sliders and gallery
|
||
|
||
Infrastructure
|
||
|
||
Technology Purpose
|
||
Docker Containerization
|
||
Docker Compose Container orchestration
|
||
Caddy Reverse proxy and HTTPS
|
||
Ansible Deployment automation
|
||
Gitea Actions CI/CD
|
||
|
||
⸻
|
||
|
||
📁 Project Structure
|
||
|
||
```
|
||
.
|
||
├── .gitea/
|
||
│ └── workflows/
|
||
│ └── ci.yml
|
||
│
|
||
├── ansible/
|
||
│ ├── deploy.yml
|
||
│ ├── inventory.ini
|
||
│ └── secrets.yml
|
||
│
|
||
├── docker/
|
||
│ ├── caddy/
|
||
│ ├── gitea_runner_image/
|
||
│ ├── gitea_runners/
|
||
│ ├── docker-compose.yaml
|
||
│ ├── dockerfile.project
|
||
│ └── start.sh
|
||
│
|
||
├── server/
|
||
│ ├── backend/
|
||
│ │ ├── auth/
|
||
│ │ │ └── JWT.py
|
||
│ │ │
|
||
│ │ ├── database/
|
||
│ │ │ ├── DB/
|
||
│ │ │ ├── alembic/
|
||
│ │ │ └── db.py
|
||
│ │ │
|
||
│ │ ├── endpoints/
|
||
│ │ │ └── endpoints.py
|
||
│ │ │
|
||
│ │ └── schema/
|
||
│ │ └── pydantic.py
|
||
│ │
|
||
│ └── frontend/
|
||
│ ├── auth/
|
||
│ │ ├── fonts/
|
||
│ │ ├── image/
|
||
│ │ ├── login.css
|
||
│ │ ├── login.html
|
||
│ │ └── login.js
|
||
│ │
|
||
│ └── main/
|
||
│ ├── fonts/
|
||
│ ├── images/
|
||
│ ├── api.js
|
||
│ ├── index.html
|
||
│ ├── main.js
|
||
│ ├── reset.css
|
||
│ └── style.css
|
||
│
|
||
├── .gitignore
|
||
├── env_example
|
||
├── makefile
|
||
├── requirements.txt
|
||
└── run.py
|
||
```
|
||
|
||
⸻
|
||
|
||
🔐 Authentication
|
||
|
||
Authentication is based on a personal access code assigned to each guest.
|
||
|
||
```
|
||
Guest
|
||
│
|
||
│ 6-digit code
|
||
▼
|
||
POST /api/auth
|
||
│
|
||
├── Validate user
|
||
├── Verify access code
|
||
├── Update last_login
|
||
└── Generate JWT
|
||
│
|
||
▼
|
||
HTTP-only Cookie
|
||
│
|
||
▼
|
||
Authenticated
|
||
```
|
||
|
||
The JWT is stored in a cookie and used for subsequent API requests.
|
||
|
||
The authentication cookie uses the following security attributes:
|
||
|
||
HttpOnly
|
||
Secure
|
||
SameSite=Strict
|
||
|
||
The JWT secret key and token configuration are provided through environment variables.
|
||
|
||
⸻
|
||
|
||
🔌 API
|
||
|
||
Main API endpoints:
|
||
|
||
Method Endpoint Description Auth
|
||
POST /api/auth Guest authentication ❌
|
||
GET /api/verify Verify authentication ✅
|
||
POST /api/logout Logout ✅
|
||
POST /api/update Update guest information ✅
|
||
POST /api/create Create a guest 👑
|
||
GET /api/list Get the guest list 👑
|
||
|
||
Where:
|
||
|
||
* ✅ — authenticated user;
|
||
* 👑 — administrator only.
|
||
|
||
Swagger
|
||
|
||
Interactive API documentation is available at:
|
||
|
||
/api/docs
|
||
|
||
ReDoc
|
||
|
||
/api/redoc
|
||
|
||
OpenAPI
|
||
|
||
/api/openapi.json
|
||
|
||
⸻
|
||
|
||
🗄️ Database
|
||
|
||
The project uses SQLite as its database.
|
||
|
||
Main entity:
|
||
|
||
users
|
||
|
||
The table contains:
|
||
|
||
* user ID;
|
||
* access code;
|
||
* first name;
|
||
* middle name;
|
||
* last name;
|
||
* personal message or request;
|
||
* food preferences;
|
||
* drink preferences;
|
||
* activation status;
|
||
* creation timestamp;
|
||
* update timestamp;
|
||
* last login timestamp;
|
||
* administrator privileges.
|
||
|
||
The database layer uses an asynchronous stack:
|
||
```
|
||
FastAPI
|
||
│
|
||
▼
|
||
SQLAlchemy 2
|
||
│
|
||
▼
|
||
aiosqlite
|
||
│
|
||
▼
|
||
SQLite
|
||
```
|
||
Database schema changes are managed using Alembic.
|
||
|
||
⸻
|
||
|
||
🚀 Local Development
|
||
|
||
Requirements
|
||
|
||
Before running the project, install:
|
||
|
||
* Python 3.13+
|
||
* pip
|
||
* SQLite
|
||
|
||
For Docker-based deployment:
|
||
|
||
* Docker
|
||
* Docker Compose
|
||
|
||
⸻
|
||
|
||
1. Clone the Repository
|
||
|
||
git clone https://git.homyk.space/MH.Dmitrii/wedding-site.git
|
||
cd wedding-site
|
||
|
||
⸻
|
||
|
||
2. Create a Virtual Environment
|
||
|
||
Linux / macOS
|
||
|
||
python3.13 -m venv .venv
|
||
source .venv/bin/activate
|
||
|
||
Windows
|
||
|
||
py -3.13 -m venv .venv
|
||
.venv\Scripts\activate
|
||
|
||
⸻
|
||
|
||
3. Install Dependencies
|
||
|
||
pip install -r requirements.txt
|
||
|
||
⸻
|
||
|
||
4. Environment Variables
|
||
|
||
Create a .env file in the project root.
|
||
```
|
||
Example:
|
||
|
||
DIR=/path/to/project
|
||
PORT=8000
|
||
SECRET_KEY=change-me
|
||
ALGORITHM=HS256
|
||
ACCESS_TOKEN_EXPIRE_SECONDS=3600
|
||
```
|
||
You can use env_example as a reference when configuring the environment.
|
||
|
||
⚠️ Never commit a real SECRET_KEY to Git.
|
||
|
||
⸻
|
||
|
||
5. Run the Application
|
||
|
||
python run.py
|
||
|
||
Or using Make:
|
||
|
||
make run
|
||
|
||
Debug mode:
|
||
|
||
make run_debug
|
||
|
||
After starting, the application will be available at:
|
||
|
||
http://localhost:8000
|
||
|
||
Swagger:
|
||
|
||
http://localhost:8000/api/docs
|
||
|
||
⸻
|
||
|
||
🐳 Docker
|
||
|
||
Docker Compose is used for production-like deployments.
|
||
|
||
Start the application:
|
||
|
||
docker compose -f docker/docker-compose.yaml up -d
|
||
|
||
Check running containers:
|
||
|
||
docker compose -f docker/docker-compose.yaml ps
|
||
|
||
View logs:
|
||
|
||
docker compose -f docker/docker-compose.yaml logs -f
|
||
|
||
Stop the application:
|
||
|
||
docker compose -f docker/docker-compose.yaml down
|
||
|
||
The SQLite database is persisted using a Docker volume, so recreating the container should not remove the database data.
|
||
|
||
⸻
|
||
|
||
🧬 Database Migrations
|
||
|
||
The project uses Alembic for database migrations.
|
||
|
||
Check the current migration:
|
||
|
||
make migrate_current
|
||
|
||
Apply all migrations:
|
||
|
||
make migrate_head
|
||
|
||
Rollback the latest migration:
|
||
|
||
make migrate_down
|
||
|
||
View migration history:
|
||
|
||
make migrate_history
|
||
|
||
View migration heads:
|
||
|
||
make migrate_heads
|
||
|
||
Create a new migration:
|
||
|
||
make migrate
|
||
|
||
⸻
|
||
|
||
⚙️ Makefile
|
||
|
||
The project provides a Makefile with shortcuts for common development and database operations.
|
||
|
||
Main commands:
|
||
|
||
make run
|
||
make run_debug
|
||
make migrate_current
|
||
make migrate_head
|
||
make migrate_down
|
||
make migrate_history
|
||
make migrate_heads
|
||
make migrate
|
||
|
||
To see all available commands:
|
||
|
||
make help
|
||
|
||
⸻
|
||
|
||
🔄 CI/CD
|
||
|
||
The project uses Gitea Actions for automation.
|
||
```
|
||
The general workflow:
|
||
|
||
git push
|
||
│
|
||
▼
|
||
┌───────────────┐
|
||
│ Gitea Actions │
|
||
└───────┬───────┘
|
||
│
|
||
┌─────────┴─────────┐
|
||
▼ ▼
|
||
Build Docker Deployment
|
||
│ │
|
||
▼ ▼
|
||
Docker Image Ansible
|
||
│
|
||
▼
|
||
Docker Compose
|
||
│
|
||
▼
|
||
Production
|
||
```
|
||
The workflow builds the Docker image and performs deployment to the target environment.
|
||
|
||
⸻
|
||
|
||
🌐 Production
|
||
```
|
||
The production infrastructure consists of:
|
||
|
||
Internet
|
||
│
|
||
▼
|
||
Caddy
|
||
│
|
||
│ HTTPS
|
||
▼
|
||
FastAPI
|
||
│
|
||
▼
|
||
SQLite
|
||
```
|
||
Caddy acts as a reverse proxy and handles external HTTP/HTTPS traffic.
|
||
|
||
Ansible is used to automate deployment and server configuration.
|
||
|
||
⸻
|
||
|
||
📱 Frontend
|
||
|
||
The frontend does not use React, Vue, Angular, or other SPA frameworks.
|
||
|
||
The main stack is:
|
||
|
||
HTML
|
||
CSS
|
||
JavaScript
|
||
|
||
This keeps the client-side application lightweight and easy to deploy.
|
||
|
||
Main pages:
|
||
|
||
/auth/login.html
|
||
/main/index.html
|
||
|
||
JavaScript is responsible for:
|
||
|
||
* authentication;
|
||
* API communication;
|
||
* mobile navigation;
|
||
* sliders;
|
||
* interactive elements;
|
||
* countdown timer;
|
||
* guest questionnaire submission.
|
||
|
||
⸻
|
||
|
||
🧪 Development
|
||
```
|
||
Recommended development workflow:
|
||
|
||
Feature branch
|
||
│
|
||
▼
|
||
Development
|
||
│
|
||
▼
|
||
Commit
|
||
│
|
||
▼
|
||
Push
|
||
│
|
||
▼
|
||
Gitea Actions
|
||
│
|
||
▼
|
||
Build
|
||
│
|
||
▼
|
||
Deploy
|
||
```
|
||
Before pushing changes, it is recommended to run:
|
||
|
||
python -m compileall .
|
||
|
||
and verify that the application starts correctly in the local environment.
|
||
|
||
⸻
|
||
|
||
🔒 Security
|
||
|
||
For production deployment, make sure to:
|
||
|
||
* use a strong, randomly generated SECRET_KEY;
|
||
* use HTTPS;
|
||
* never commit .env files to Git;
|
||
* never store production secrets in plain text;
|
||
* restrict access to the SQLite database;
|
||
* regularly back up the database;
|
||
* disable debug mode in production.
|
||
|
||
⚠️ Deployment configuration and secrets should be reviewed carefully before making the repository public.
|
||
|
||
⸻
|
||
|
||
🗺️ Roadmap
|
||
|
||
Possible future improvements:
|
||
|
||
* Add comprehensive automated tests
|
||
* Add API test coverage
|
||
* Add SQLite backup and restore
|
||
* Add a dedicated admin frontend
|
||
* Add guest response statistics
|
||
* Add guest list export to Excel/CSV
|
||
* Add rate limiting to /api/auth
|
||
* Add CSRF protection for cookie-based authentication
|
||
* Add centralized logging
|
||
* Add a dedicated healthcheck endpoint
|
||
* Add application monitoring
|
||
|
||
⸻
|
||
|
||
📊 Project
|
||
```
|
||
Main languages used in the project:
|
||
|
||
HTML ████████████████████ 40.5%
|
||
CSS ███████████████ 29.5%
|
||
Python ██████████ 20.9%
|
||
JavaScript ████ 7.6%
|
||
Makefile ▏ 0.7%
|
||
|
||
The statistics are based on the current state of the repository.
|
||
```
|
||
⸻
|
||
|
||
📄 License
|
||
|
||
No explicit license is currently specified in the repository.
|
||
|
||
If the project is intended to be distributed as open source, it is recommended to add a:
|
||
|
||
LICENSE
|
||
|
||
file and specify the chosen license in this section.
|
||
|
||
⸻
|
||
|
||
👨💻 Author
|
||
|
||
MH.Dmitrii
|
||
|
||
Repository:
|
||
|
||
https://git.homyk.space/MH.Dmitrii/wedding-site
|