-
Notifications
You must be signed in to change notification settings - Fork 0
Local development stack: infra-only compose for martyrology-api #29
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
23 commits
Select commit
Hold shift + click to select a range
a6b79c9
Design the local development stack
JohnRDOrazio 45f83e6
Plan the local development stack implementation
JohnRDOrazio 3b25702
Add MARTYROLOGY_ZITADEL_INTERNAL_URL for introspection transport
JohnRDOrazio 088813d
Add the martyrology database setting and an Alembic baseline
JohnRDOrazio 90dfe24
Add the API Dockerfile and database bootstrap SQL
JohnRDOrazio e8b7a26
Pin Dockerfile base image and data repo refs; scope init-db.sql crede…
JohnRDOrazio b87c37e
Add the minimal stack: Postgres, Zitadel, Mailpit, Adminer
JohnRDOrazio 5c6e0d3
Fix ZITADEL_PORT override: parameterize EXTERNALPORT to match the pub…
JohnRDOrazio 115fa58
Add OpenFGA and seed the Martyrology store from cdcf-infra
JohnRDOrazio 2436671
Add the api-migrate one-shot Alembic service
JohnRDOrazio cb50bfd
Fix api-migrate tag collision and .env.example password mismatch
JohnRDOrazio fd5b218
Add local stack provisioning and superuser grant scripts
JohnRDOrazio ac6291b
Fix review findings in stack provisioning scripts
JohnRDOrazio e277eb3
Fix fd-2 leak in grant-superuser.sh's terminal-open check
JohnRDOrazio 4a3215c
Add the minimal-stack smoke test and document the bring-up
JohnRDOrazio 07a0e8b
Broaden .env gitignore to cover all variants; document host prerequis…
JohnRDOrazio 5fd7e46
Remove phantom python3 prerequisite from README
JohnRDOrazio f3e6d87
Add reciprocal SIBLING NOTE headers pointing at martyrology-frontend
JohnRDOrazio 545512b
Fix local-dev-stack review findings: unreachable diagnostics, cut tru…
JohnRDOrazio f608f50
Merge remote-tracking branch 'origin/main' into feat/local-dev-stack
JohnRDOrazio a6798ec
Address CodeRabbit PR #29 review findings
JohnRDOrazio 68664ca
Fix pagination guard in smoke.sh (sibling of frontend PR #16 round 2 …
JohnRDOrazio d257669
Bound every curl in scripts/*.sh with connect/max-time timeouts
JohnRDOrazio File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| # Deny-all, then re-admit exactly what the image needs. `vendor/` is excluded | ||
| # on purpose: vendor/texts is a PRIVATE submodule, and crmedr/clbdr are cloned | ||
| # in the build instead (see the Dockerfile). | ||
| * | ||
| !pyproject.toml | ||
| !uv.lock | ||
| !src | ||
| !data | ||
| !alembic | ||
| !alembic.ini | ||
| !scripts | ||
| **/__pycache__ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
| # martyrology-api image. | ||
| # | ||
| # Consumed by martyrology-frontend's full docker stack and by CI. The API | ||
| # repo's own compose stack is infra-only — local API development runs | ||
| # `uvicorn --factory --reload` on the host, so this image is never in that | ||
| # edit loop. See docs/superpowers/specs/2026-08-04-local-development-stack-design.md, D4. | ||
|
|
||
| FROM python:3.12.13-slim AS build | ||
|
|
||
| # Pinned refs for the two data repositories — these SHAs are the commits this | ||
| # repo's own vendor/ submodules record, so the image and vendor/ agree. To | ||
| # bump the data revision intentionally, pass a new SHA with --build-arg. | ||
| ARG CRMEDR_REF=51740e79584f64940f9e3f98615b000ef5f77e92 | ||
| ARG CLBDR_REF=ecb147b47b47368fbdefeb2074c5770ebb7c8f9d | ||
|
|
||
| RUN apt-get update -y && \ | ||
| apt-get install -y --no-install-suggests --no-install-recommends \ | ||
| git ca-certificates && \ | ||
| rm -rf /var/lib/apt/lists/* | ||
|
|
||
| COPY --from=ghcr.io/astral-sh/uv:0.9.6 /uv /usr/local/bin/uv | ||
|
|
||
| WORKDIR /app | ||
| COPY pyproject.toml uv.lock ./ | ||
| COPY src ./src | ||
| RUN uv sync --frozen --no-dev | ||
|
|
||
| # app.py calls Registry.load(crmedr_path, clbdr_path) at startup and | ||
| # registry.py reads four files from them unconditionally — the API cannot boot | ||
| # without these. They are CLONED rather than COPYed from vendor/ because | ||
| # vendor/texts is a PRIVATE submodule: a recursive clone of a GitHub build | ||
| # context would fail for anyone without access to it. | ||
| # | ||
| # CRMEDR_REF/CLBDR_REF are commit SHAs, not branch names, so `git clone | ||
| # --branch` can't be used (it only accepts refs GitHub advertises, not | ||
| # arbitrary SHAs). init+fetch+checkout fetches the exact commit instead. | ||
| RUN git init /data/crmedr && \ | ||
| git -C /data/crmedr remote add origin https://github.com/CatholicOS/crmedr.git && \ | ||
| git -C /data/crmedr fetch --depth 1 origin "$CRMEDR_REF" && \ | ||
| git -C /data/crmedr checkout FETCH_HEAD && \ | ||
| git init /data/clbdr && \ | ||
| git -C /data/clbdr remote add origin https://github.com/CatholicOS/clbdr.git && \ | ||
| git -C /data/clbdr fetch --depth 1 origin "$CLBDR_REF" && \ | ||
| git -C /data/clbdr checkout FETCH_HEAD && \ | ||
| rm -rf /data/crmedr/.git /data/clbdr/.git | ||
|
|
||
|
|
||
| FROM python:3.12.13-slim AS main | ||
|
|
||
| WORKDIR /app | ||
|
|
||
| RUN useradd -m -u 1000 martyrology | ||
|
|
||
| COPY --from=build --chown=martyrology:martyrology /app/.venv /app/.venv | ||
| COPY --from=build --chown=martyrology:martyrology /data /data | ||
| # Load-bearing, not redundant with the copied .venv: `uv sync` in the build | ||
| # stage produced an editable install whose .pth file points at the literal | ||
| # path /app/src, so this WORKDIR/COPY pair must keep matching the build | ||
| # stage's or every import breaks silently at first boot. | ||
| COPY --chown=martyrology:martyrology src ./src | ||
| COPY --chown=martyrology:martyrology data ./data | ||
| COPY --chown=martyrology:martyrology alembic ./alembic | ||
| COPY --chown=martyrology:martyrology alembic.ini ./ | ||
| COPY --chown=martyrology:martyrology scripts/init-db.sql ./scripts/init-db.sql | ||
|
|
||
| ENV PATH="/app/.venv/bin:$PATH" \ | ||
| MARTYROLOGY_CRMEDR_PATH=/data/crmedr \ | ||
| MARTYROLOGY_CLBDR_PATH=/data/clbdr \ | ||
| MARTYROLOGY_DATA_PATH=/app/data/editions | ||
|
|
||
| USER martyrology | ||
|
|
||
| EXPOSE 8000 | ||
|
|
||
| CMD ["uvicorn", "martyrology_api.app:create_app", "--factory", \ | ||
| "--host", "0.0.0.0", "--port", "8000"] | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| [alembic] | ||
| script_location = alembic | ||
| prepend_sys_path = . | ||
| version_path_separator = os | ||
|
|
||
| [loggers] | ||
| keys = root,sqlalchemy,alembic | ||
|
|
||
| [handlers] | ||
| keys = console | ||
|
|
||
| [formatters] | ||
| keys = generic | ||
|
|
||
| [logger_root] | ||
| level = WARNING | ||
| handlers = console | ||
| qualname = | ||
|
|
||
| [logger_sqlalchemy] | ||
| level = WARNING | ||
| handlers = | ||
| qualname = sqlalchemy.engine | ||
|
|
||
| [logger_alembic] | ||
| level = INFO | ||
| handlers = | ||
| qualname = alembic | ||
|
|
||
| [handler_console] | ||
| class = StreamHandler | ||
| args = (sys.stderr,) | ||
| level = NOTSET | ||
| formatter = generic | ||
|
|
||
| [formatter_generic] | ||
| format = %(levelname)-5.5s [%(name)s] %(message)s | ||
| datefmt = %H:%M:%S |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| """Alembic environment. | ||
|
|
||
| The DSN comes from MARTYROLOGY_DATABASE_URL rather than alembic.ini so the | ||
| one-shot `api-migrate` compose service and a developer shell configure it the | ||
| same way. There is no target metadata yet: this tree exists to establish the | ||
| migration contract, and autogenerate is deliberately not wired up until the | ||
| permission-request subsystem introduces models. | ||
| """ | ||
|
|
||
| import os | ||
| from logging.config import fileConfig | ||
|
|
||
| from alembic import context | ||
| from sqlalchemy import engine_from_config, pool | ||
|
|
||
| config = context.config | ||
|
|
||
| if config.config_file_name is not None: | ||
| fileConfig(config.config_file_name) | ||
|
|
||
| DATABASE_URL = os.environ.get("MARTYROLOGY_DATABASE_URL", "") | ||
| if DATABASE_URL: | ||
| config.set_main_option("sqlalchemy.url", DATABASE_URL) | ||
|
|
||
| target_metadata = None | ||
|
|
||
|
|
||
| def run_migrations_offline() -> None: | ||
| context.configure( | ||
| url=config.get_main_option("sqlalchemy.url"), | ||
| target_metadata=target_metadata, | ||
| literal_binds=True, | ||
| dialect_opts={"paramstyle": "named"}, | ||
| ) | ||
| with context.begin_transaction(): | ||
| context.run_migrations() | ||
|
|
||
|
|
||
| def run_migrations_online() -> None: | ||
| connectable = engine_from_config( | ||
| config.get_section(config.config_ini_section, {}), | ||
| prefix="sqlalchemy.", | ||
| poolclass=pool.NullPool, | ||
| ) | ||
| with connectable.connect() as connection: | ||
| context.configure(connection=connection, target_metadata=target_metadata) | ||
| with context.begin_transaction(): | ||
| context.run_migrations() | ||
|
|
||
|
|
||
| if context.is_offline_mode(): | ||
| run_migrations_offline() | ||
| else: | ||
| run_migrations_online() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| """${message} | ||
|
|
||
| Revision ID: ${up_revision} | ||
| Revises: ${down_revision | comma,n} | ||
| Create Date: ${create_date} | ||
| """ | ||
|
|
||
| from alembic import op | ||
| import sqlalchemy as sa | ||
| ${imports if imports else ""} | ||
|
|
||
| revision = ${repr(up_revision)} | ||
| down_revision = ${repr(down_revision)} | ||
| branch_labels = ${repr(branch_labels)} | ||
| depends_on = ${repr(depends_on)} | ||
|
|
||
|
|
||
| def upgrade() -> None: | ||
| ${upgrades if upgrades else "pass"} | ||
|
|
||
|
|
||
| def downgrade() -> None: | ||
| ${downgrades if downgrades else "pass"} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| """Baseline — establishes the migration contract, creates no tables. | ||
|
|
||
| martyrology-api has no application tables yet. This revision exists so that a | ||
| fresh `alembic upgrade head` succeeds against an empty `martyrology` database | ||
| and stamps a version, which is what the `api-migrate` compose service asserts. | ||
| The permission-request and notification subsystem adds real tables on top. | ||
|
|
||
| Revision ID: 0001_baseline | ||
| Revises: | ||
| """ | ||
|
|
||
| revision = "0001_baseline" | ||
| down_revision = None | ||
| branch_labels = None | ||
| depends_on = None | ||
|
|
||
|
|
||
| def upgrade() -> None: | ||
| pass | ||
|
|
||
|
|
||
| def downgrade() -> None: | ||
| pass |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.