Skip to content

Commit c41f4df

Browse files
authored
ft/add alembic support (#77)
Fixes #76
2 parents d1f02d0 + ea6d004 commit c41f4df

File tree

12 files changed

+1285
-6
lines changed

12 files changed

+1285
-6
lines changed

backend/README.md

Lines changed: 79 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,12 @@ backend/
3636
│ │ └── auth.py # JWT and permission handling
3737
│ └── utils/ # Utility functions
3838
│ └── __init__.py # Utility functions module
39-
├── migrations/ # Database migration scripts
39+
├── alembic/ # Alembic migration environment
40+
│ ├── env.py # Alembic environment configuration
41+
│ ├── versions/ # Migration version files
42+
│ ├── script.py.mako # Migration template
43+
│ └── README.md # Alembic documentation
44+
├── migrations/ # Custom migration scripts (one-time/data migrations)
4045
│ ├── README.md
4146
│ ├── add_article_metadata_to_submissions.py
4247
│ ├── add_expansion_bytes_to_submissions.py
@@ -53,7 +58,11 @@ backend/
5358
│ └── toolforge_requirements.txt
5459
├── tests/ # Test files (pytest)
5560
├── logs/ # Application logs
61+
├── docs/ # Documentation
62+
│ ├── ALEMBIC_USAGE_GUIDE.md # Detailed Alembic usage guide
5663
├── main.py # Main entry point for running the app
64+
├── alembic.ini # Alembic configuration file
65+
├── Makefile # Makefile for common commands
5766
├── requirements.txt # Python dependencies
5867
├── setup.py # Setup script
5968
├── deploy_to_toolforge.sh # Deployment script
@@ -117,7 +126,21 @@ backend/
117126

118127
## Running the Application
119128

120-
### Development Mode
129+
### Using Makefile (Recommended)
130+
131+
The Makefile provides convenient commands for common tasks:
132+
133+
```bash
134+
# Run the development server
135+
make run
136+
# or
137+
make dev
138+
139+
# View all available commands
140+
make help
141+
```
142+
143+
### Manual Running
121144

122145
1. **Start the Flask development server:**
123146
```bash
@@ -247,6 +270,14 @@ Located in `app/middleware/auth.py`:
247270
## Development
248271

249272
### Running Tests
273+
274+
**Using Makefile:**
275+
```bash
276+
make test # Run tests
277+
make test-coverage # Run tests with coverage report
278+
```
279+
280+
**Direct pytest commands:**
250281
```bash
251282
# Install test dependencies
252283
pip install pytest pytest-flask
@@ -260,14 +291,58 @@ The code follows Python PEP 8 standards with comprehensive comments and document
260291

261292
### Database Migrations
262293

263-
The application includes custom migration scripts in the `migrations/` directory. Migrations are automatically run on application startup, or can be run manually:
294+
The application uses **Alembic** for database migrations, which provides robust database schema versioning and management.
295+
296+
#### Using Alembic
297+
298+
```bash
299+
# Create a new migration (after modifying models)
300+
alembic revision --autogenerate -m "Description of changes"
301+
302+
# Apply migrations
303+
alembic upgrade head
304+
305+
# Rollback to previous version
306+
alembic downgrade -1
307+
308+
# View current migration status
309+
alembic current
310+
311+
# View migration history
312+
alembic history
313+
```
314+
315+
#### How Alembic Works
316+
317+
1. **Migration Files**: Python files in `alembic/versions/` define schema changes
318+
2. **Version Tracking**: `alembic_version` table in database stores current version
319+
3. **Migration Chain**: Each migration points to the previous one (linked list structure)
320+
4. **Upgrade/Downgrade**: Each migration has functions to apply and reverse changes
321+
322+
#### Typical Workflow
323+
324+
1. Modify your models in `app/models/`
325+
2. Generate migration: `make migrate-create MSG="Add new field"`
326+
3. Review the generated file in `alembic/versions/`
327+
4. Apply migration: `make db-upgrade`
328+
5. Test your application
329+
6. Commit migration file to version control
330+
331+
For detailed Alembic documentation, see:
332+
- [`docs/ALEMBIC_USAGE_GUIDE.md`](docs/ALEMBIC_USAGE_GUIDE.md) - Complete usage guide
333+
- [`docs/ALEMBIC_MODEL_COMPATIBILITY.md`](docs/ALEMBIC_MODEL_COMPATIBILITY.md) - Model compatibility guide
334+
- [`docs/ALEMBIC_SETUP_VERIFICATION.md`](docs/ALEMBIC_SETUP_VERIFICATION.md) - Setup verification checklist
335+
336+
#### Legacy Migration Scripts
337+
338+
The application also includes custom migration scripts in the `migrations/` directory for reference. These can be run manually if needed:
264339

265340
```bash
266341
# Run a specific migration
267342
python migrations/add_article_metadata_to_submissions.py
268343
```
269344

270-
For production deployments, consider using Flask-Migrate (Alembic) for more robust database schema versioning.
345+
**Note**: For new schema changes, use Alembic migrations instead of custom scripts.
271346

272347
### Utility Scripts
273348

backend/alembic.ini

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
# A generic, single database configuration.
2+
3+
[alembic]
4+
# path to migration scripts
5+
script_location = alembic
6+
7+
# template used to generate migration file names; The default value is %%(rev)s_%%(slug)s
8+
# Uncomment the line below if you want the files to be prepended with date and time
9+
# file_template = %%(year)d_%%(month).2d_%%(day).2d_%%(hour).2d%%(minute).2d-%%(rev)s_%%(slug)s
10+
11+
# sys.path path, will be prepended to sys.path if present.
12+
# defaults to the current working directory.
13+
prepend_sys_path = .
14+
15+
# timezone to use when rendering the date within the migration file
16+
# as well as the filename.
17+
# If specified, requires the python-dateutil library that can be
18+
# installed by adding `alembic[tz]` to the pip requirements
19+
# string value is passed to dateutil.tz.gettz()
20+
# leave blank for localtime
21+
# timezone =
22+
23+
# max length of characters to apply to the
24+
# "slug" field
25+
# truncate_slug_length = 40
26+
27+
# set to 'true' to run the environment during
28+
# the 'revision' command, regardless of autogenerate
29+
# revision_environment = false
30+
31+
# set to 'true' to allow .pyc and .pyo files without
32+
# a source .py file to be detected as revisions in the
33+
# versions/ directory
34+
# sourceless = false
35+
36+
# version location specification; This defaults
37+
# to alembic/versions. When using multiple version
38+
# directories, initial revisions must be specified with --version-path.
39+
# The path separator used here should be the separator specified by "version_path_separator" below.
40+
# version_locations = %(here)s/bar:%(here)s/bat:alembic/versions
41+
42+
# version path separator; As mentioned above, this is the character used to split
43+
# version_locations. The default within new alembic.ini files is "os", which uses os.pathsep.
44+
# If this key is omitted entirely, it falls back to the legacy behavior of splitting on spaces and/or commas.
45+
# Valid values for version_path_separator are:
46+
#
47+
# version_path_separator = :
48+
# version_path_separator = ;
49+
# version_path_separator = space
50+
version_path_separator = os # Use os.pathsep. Default configuration used for new projects.
51+
52+
# set to 'true' to search source files recursively
53+
# in each "version_locations" directory
54+
# new in Alembic version 1.10
55+
# recursive_version_locations = false
56+
57+
# the output encoding used when revision files
58+
# are written from script.py.mako
59+
# output_encoding = utf-8
60+
61+
# Database URL is automatically retrieved from Flask app configuration
62+
# Do not set sqlalchemy.url here - it will be read from app.config['SQLALCHEMY_DATABASE_URI']
63+
# sqlalchemy.url = driver://user:pass@localhost/dbname
64+
65+
66+
[post_write_hooks]
67+
# post_write_hooks defines scripts or Python functions that are run
68+
# on newly generated revision scripts. See the documentation for further
69+
# detail and examples
70+
71+
# format using "black" - use the console_scripts runner, against the "black" entrypoint
72+
# hooks = black
73+
# black.type = console_scripts
74+
# black.entrypoint = black
75+
# black.options = -l 79 REVISION_SCRIPT_FILENAME
76+
77+
# lint with attempts to fix using "ruff" - use the exec runner, execute a binary
78+
# hooks = ruff
79+
# ruff.type = exec
80+
# ruff.executable = %(here)s/.venv/bin/ruff
81+
# ruff.options = --fix REVISION_SCRIPT_FILENAME
82+
83+
# Logging configuration
84+
[loggers]
85+
keys = root,sqlalchemy,alembic
86+
87+
[handlers]
88+
keys = console
89+
90+
[formatters]
91+
keys = generic
92+
93+
[logger_root]
94+
level = WARN
95+
handlers = console
96+
qualname =
97+
98+
[logger_sqlalchemy]
99+
level = WARN
100+
handlers =
101+
qualname = sqlalchemy.engine
102+
103+
[logger_alembic]
104+
level = INFO
105+
handlers =
106+
qualname = alembic
107+
108+
[handler_console]
109+
class = StreamHandler
110+
args = (sys.stderr,)
111+
level = NOTSET
112+
formatter = generic
113+
114+
[formatter_generic]
115+
format = %(levelname)-5.5s [%(name)s] %(message)s
116+
datefmt = %H:%M:%S
117+

0 commit comments

Comments
 (0)