Skip to content
Merged

V0.1 #10

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Copy this file to .env and fill in the values.
# .env is git-ignored; .env.example is committed.

# Required — SQLAlchemy database URL
# SQLite (development):
DATABASE_URL=sqlite:///./app.db
# PostgreSQL (production):
# DATABASE_URL=postgresql+psycopg://user:password@localhost:5432/mydb

# Required — secret key for session signing (use a long random string in production)
SECRET_KEY=change-me-in-production
94 changes: 94 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
name: CI

on:
push:
branches: ["main", "dev", "v0.1"]
pull_request:
branches: ["main"]

concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true

jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
cache: pip

- name: Install dev dependencies
run: pip install -e ".[dev]"

- name: black
run: black --check internal_admin tests

- name: isort
run: isort --check-only internal_admin tests

- name: ruff
run: ruff check internal_admin tests

typecheck:
name: Type check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
cache: pip

- name: Install dev dependencies
run: pip install -e ".[dev]"

- name: mypy
run: mypy internal_admin

test:
name: Test (Python ${{ matrix.python-version }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: ["3.10", "3.11", "3.12"]

steps:
- uses: actions/checkout@v4

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: pip

- name: Install dependencies
run: pip install -e ".[dev]"

- name: Run tests with coverage
run: |
pytest tests/ \
--cov=internal_admin \
--cov-report=xml \
--cov-report=term-missing \
-v
env:
DATABASE_URL: sqlite:///./test.db
SECRET_KEY: ci-test-secret-key

- name: Upload coverage report
uses: codecov/codecov-action@v4
if: matrix.python-version == '3.12'
with:
file: ./coverage.xml
fail_ci_if_error: false
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
63 changes: 63 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
name: Release

on:
push:
branches: ["main"]

# Only one release job runs at a time; queued runs wait rather than cancel.
concurrency:
group: release
cancel-in-progress: false

jobs:
release:
name: Semantic release
runs-on: ubuntu-latest

# Prevent release from running on the automated version-bump commit itself.
if: "!contains(github.event.head_commit.message, '[skip ci]')"

permissions:
id-token: write # required for PyPI trusted publishing
contents: write # required to push the version-bump commit and tag

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # full history needed for semantic-release
token: ${{ secrets.GH_TOKEN }}

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.12"
cache: pip

- name: Install dev dependencies
run: pip install -e ".[dev]"

- name: Configure git identity
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"

# python-semantic-release will:
# 1. Analyse commits since the last tag using Conventional Commits
# 2. Determine the version bump (patch / minor / major)
# 3. Update pyproject.toml and internal_admin/__init__.py
# 4. Update CHANGELOG.md
# 5. Commit, tag, and push
# 6. Build the sdist + wheel
# 7. Create a GitHub release and attach the build artefacts
# 8. Publish to PyPI via trusted publishing (OIDC — no token stored)
- name: Run semantic release
id: semantic
run: semantic-release version
env:
GH_TOKEN: ${{ secrets.GH_TOKEN }}

- name: Publish to PyPI
if: steps.semantic.outputs.released == 'true'
run: semantic-release publish
env:
GH_TOKEN: ${{ secrets.GH_TOKEN }}
10 changes: 9 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -216,4 +216,12 @@ cookies.txt
ai_contribute.md

# sqlite db
*.db
*.db

# Release build artefacts
dist/
build/

# .env — never commit credentials; commit .env.example instead
.env
.DS_Store
54 changes: 54 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
repos:
# General hygiene
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.6.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-toml
- id: check-json
- id: check-merge-conflict
- id: check-added-large-files
args: ["--maxkb=500"]
- id: debug-statements
- id: mixed-line-ending
args: ["--fix=lf"]

# Python import sorting
- repo: https://github.com/pycqa/isort
rev: 5.13.2
hooks:
- id: isort
args: ["--profile", "black"]

# Python formatting
- repo: https://github.com/psf/black
rev: 24.4.2
hooks:
- id: black

# Fast linting
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.4.4
hooks:
- id: ruff
args: ["--fix"]

# Conventional commit message enforcement
- repo: https://github.com/compilerla/conventional-pre-commit
rev: v3.4.0
hooks:
- id: conventional-pre-commit
stages: [commit-msg]
args:
- feat
- fix
- perf
- refactor
- docs
- style
- test
- chore
- ci
- build
78 changes: 49 additions & 29 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,62 @@

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
Releases are automated via [python-semantic-release](https://python-semantic-release.readthedocs.io/)
using [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/).

### Added
- Initial project structure
- Core architecture design
- AdminSite, ModelAdmin, AdminConfig public API
- SQLAlchemy 2.0 integration planning
- Authentication system design
- Permission system architecture
- Query engine design
- Form engine planning
- Bootstrap 5 template structure
- Development environment setup
---

### Changed
- N/A
## [Unreleased]

### Deprecated
- N/A
---

### Removed
- N/A
## [0.1.0] - 2026-03-04

### Fixed
- N/A
### Added

- `AdminSite`, `ModelAdmin`, and `AdminConfig` as the stable public API
- Automatic CRUD route generation per registered SQLAlchemy model
(`GET`/`POST` list, create, edit, delete with confirmation)
- Model registry with validation (primary key presence, declarative model check,
duplicate registration guard)
- Query engine with search, boolean/foreign-key filters, configurable ordering,
and pagination — all in a single pipeline
- Form engine: SQLAlchemy column introspection mapping types to HTML widgets
(text, textarea, checkbox, datetime-local, number, select)
- Session-based authentication with HTTP-only cookies and bcrypt password hashing
- Built-in `AdminUser` model (`admin_users` table) with `username`, `email`,
`is_active`, `is_superuser`, `created_at`, `last_login`
- `internal-admin createsuperuser` CLI command — reads `DATABASE_URL` and
`SECRET_KEY` from environment or `.env` file; no default users are ever seeded
- Activity logging: `ActivityLog` model records create, update, delete, and login
events with user, IP, user-agent, and timestamp
- Dashboard showing registered model counts and the 10 most recent activity
log entries
- Bootstrap 5 server-rendered UI (sidebar, navbar, list, form, confirm-delete
templates) — no JavaScript frameworks, no build pipeline
- Standalone login page (no sidebar/navbar) with client-side field validation,
show/hide password toggle, and loading state
- Logout confirmation modal
- User profile modal accessible from the navbar dropdown (display name, email,
role badge, member-since, last-login)
- `python-dotenv` integration: `.env` file loaded automatically in both the CLI
and demo server
- `demo_web.py` demo server registering `DemoCategory`, `DemoProduct`, and
`AdminUser` in the admin panel
- `CONTRIBUTING.md` and `CODE_OF_CONDUCT.md`

### Security
- N/A

## [0.1.0] - 2026-02-25
- Passwords are hashed with bcrypt via passlib; plaintext passwords are never
stored or logged
- Session cookies are HTTP-only
- `password_hash` excluded from all admin forms by default when `AdminUser` is
registered

### Added
- Initial project setup
- Project architecture documentation
- Contributing guidelines
- Development environment configuration
---

[Unreleased]: https://github.com/ayahaustine/internal-admin/compare/v0.1.0...HEAD
[0.1.0]: https://github.com/ayahaustine/internal-admin/releases/tag/v0.1.0
Loading
Loading