Skip to content
Draft
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
28 changes: 28 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Dockette / Adminer

Adminer database UI served by the PHP built-in web server, one image per database driver set.

## Stack

- Docker image built with `docker buildx`, base `alpine:3.23` or `dockette/debian:bookworm-slim` (MS SQL, Oracle)
- Adminer 6.1.0 on PHP 8
- Published to Docker Hub as `dockette/adminer` for linux/amd64 and linux/arm64 by GitHub Actions

## Development

```bash
make build # build all variant images
make test # smoke test all variant images
make run # run one image on port 8000 (DOCKER_RUN_TAG=full)
make build-full # build one variant; also test-full, run-full
```

Run `make` to list every target.

## Principles

- KISS: one image does one job; no extra services or tools.
- DRY: shared steps live in the base image, not copied into every Dockerfile.
- YAGNI: add a package only when the image needs it.
- Pin versions, keep layers small, clean package caches in the same `RUN`.
- Every change is built and smoke tested with `make build test` before a commit.
104 changes: 104 additions & 0 deletions DESIGN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# Adminer Design

The Adminer images serve the Adminer database UI on port `80`. Developers open it in a browser to inspect and
edit databases in local and staging stacks. The UI is upstream [Adminer](https://www.adminer.org); this file
describes only what the image adds on top of it.

## Principles

- **Upstream UI, unmodified PHP.** The `Dockerfile` downloads the release file `adminer-{version}.php` (or
`editor-{version}.php`) to `/srv/index.php`; nothing patches it.
- **Everything is opt-in by environment.** Themes and plugins are off until a variable turns them on, so a
container started with no variables looks like upstream Adminer. The one exception is `mssql`, where
`mssql-encrypt` is on by default.
- **Credentials never reach the browser.** The server list and autologin plugins parse DSNs from the environment
on the server; the page only receives server names.
- **One entrypoint per variant.** Each `adminer-{tag}/entrypoint.sh` enables only the features its variant
supports.

## Inventory

- Login and database screens: upstream `adminer-{version}.php`, served as `/srv/index.php` (`ADMINER_VERSION`).
- Editor screens (`editor` tag): upstream `editor-{version}.php`, the data-only Adminer Editor.
- Server dropdown with Auto Sign-In: `.plugins/adminer-server-list.php`, enabled by `ADMINER_PLUGIN_SERVER_LIST=1`.
- Autologin, which skips the login form: `.plugins/adminer-autologin.php`, enabled by `ADMINER_PLUGIN_AUTOLOGIN=1`.
- MSSQL encryption options: `.plugins/adminer-mssql-encrypt.php`, `mssql` tag only, on unless
`ADMINER_PLUGIN_MSSQL_ENCRYPT=0`.
- Upstream driver plugins: the release `plugins/drivers/` folder, copied into `/srv/adminer-plugins/` at start,
`full` tag only.
- Themes: the release `designs/` folder, copied to `/srv/designs/` at build time (not in `dg`).
- The `dg` tag serves the separate `adminer-custom` project with its own look. None of the plugins or themes
above apply to it.
- The other variants differ in drivers, not in UI: `full`, `mysql`, `postgres`, `mongo`, `mssql`, `oracle-*`.

## Layout

- Upstream. The server list plugin changes the login form: the Server text field becomes a `<select>` of the
names from `ADMINER_SERVERS_*`, the System (driver) field disappears because the driver comes from the DSN, and
an Auto Sign-In button appears next to Login.
- Autologin removes the login form from the first visit; the user lands on the database screen.

## Typography

- Upstream theme, or the fonts of the selected design.

## Colors and Themes

- Themes come from the upstream release `designs/` folder, copied to `/srv/designs/` at build time. The list
changes with the Adminer version.
- `ADMINER_THEME={name}` copies `/srv/designs/{name}/adminer.css` to `/srv/adminer.css` at start, where Adminer
picks it up, and `adminer-dark.css` too when the theme has one.
- Default: no theme file, upstream look.

## States

- Every start prints a banner (off with `ADMINER_BANNER=0`), `[adminer] Loading Adminer...` and the PHP server
settings (`memory_limit`, upload limits, port). `ADMINER_DEBUG=1` adds shell tracing.
- Theme applied: `[adminer] Theme '{name}' applied successfully.`
- Unknown theme: a warning and the list of available themes; the UI stays default.
- Theme folder without `adminer.css`: a warning; the UI stays default.
- Plugin enabled: `[adminer] Plugin '{name}' activated.`
- Autologin and server list both enabled: only autologin is activated.
- Server without credentials in its DSN: listed in the dropdown, but needs a manual login; no Auto Sign-In button.
- Invalid DSN: the plugin skips it silently; the server is not listed.

## Accessibility

- Upstream HTML forms. The server list plugin uses the upstream `<select>` helper and a plain
`<input type="submit">`, both keyboard reachable. Its button is hidden with `display: none` for servers without
credentials.

## Dark Mode

- Only through a theme that ships `adminer-dark.css`; how it is switched on is upstream behaviour.

## Responsive

- Desktop first, as upstream. Our plugins add no layout of their own and are not tested on narrow screens.

## Screenshots

- `.docs/assets/adminer.png` (default look), `.docs/assets/adminer-dg.png` (`dg` tag) and
`.docs/assets/themes/{name}.png`, one per theme, shown 200 px wide in the README table.
- To retake one, run `make build-full`, then `docker run --rm -p 8000:80 -e ADMINER_THEME={name}
dockette/adminer:full`, open `http://localhost:8000` and capture the login screen.
- After an Adminer version bump, retake the default screenshot and check the theme list against `designs/`.

## Changing the UI

- Variable names (`ADMINER_THEME`, `ADMINER_PLUGIN_*`, `ADMINER_SERVERS_*`, `ADMINER_AUTOLOGIN_SERVER`) are
public; rename them only with a deprecation note in the README.
- A new upstream major can change the plugin API (`Adminer\Plugin`, `loginFormField`, `credentials`); start
every variant and log in once.
- The server list script finds the Login button by `value="Login"`; an upstream label change hides the Auto
Sign-In button.
- Adding a theme to the README table needs its screenshot in `.docs/assets/themes/`.

## Checklist

- [ ] The default container (no variables) looks like upstream Adminer
- [ ] Each changed plugin tested with and without credentials, in `full` and one Debian variant
- [ ] `ADMINER_THEME` with a valid and an invalid name
- [ ] No DSN or password appears in the page source
- [ ] `mssql` still connects with `ADMINER_PLUGIN_MSSQL_ENCRYPT` unset and set to `0`
- [ ] Screenshots updated if the UI changed
161 changes: 121 additions & 40 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,62 +3,143 @@ DOCKER_PLATFORMS?=linux/amd64
DOCKER_RUN_PORT?=8000
DOCKER_RUN_TAG?=full

build: build-all
.DEFAULT_GOAL := help

test: test-all
##@ Help

run:
.PHONY: help
help: ## Show this help
@awk 'BEGIN {FS = ":.*##"; printf "Usage: make \033[36m<target>\033[0m\n"} /^[a-zA-Z0-9_.-]+:.*##/ { sub(/^ +/, "", $$2); printf " \033[36m%-20s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) }' $(firstword $(MAKEFILE_LIST))

##@ Docker

.PHONY: build
build: build-all ## Build all variant images

.PHONY: test
test: test-all ## Test all variant images

.PHONY: run
run: ## Run one image on port 8000 (DOCKER_RUN_TAG=full)
docker run --rm -it -p ${DOCKER_RUN_PORT}:80 ${DOCKER_IMAGE}:${DOCKER_RUN_TAG}

build-all: build-full build-dg build-editor build-mongo build-mssql build-mysql build-postgres build-oracle-11 build-oracle-12 build-oracle-19
.PHONY: build-all
build-all: build-full build-dg build-editor build-mongo build-mssql build-mysql build-postgres build-oracle-11 build-oracle-12 build-oracle-19 ## Build all variant images

.PHONY: test-all
test-all: test-full test-dg test-editor test-mongo test-mssql test-mysql test-postgres test-oracle-11 test-oracle-12 test-oracle-19 ## Run php --version in all variant images

_docker-build-%: TAG=$*
_docker-build-%:
docker buildx build --platform ${DOCKER_PLATFORMS} -t ${DOCKER_IMAGE}:${TAG} -f ./adminer-${TAG}/Dockerfile .

build-full: _docker-build-full
build-dg: _docker-build-dg
build-editor: _docker-build-editor
build-mongo: _docker-build-mongo
build-mssql: _docker-build-mssql
build-mysql: _docker-build-mysql
build-postgres: _docker-build-postgres
build-oracle-11: _docker-build-oracle-11
build-oracle-12: _docker-build-oracle-12
build-oracle-19: _docker-build-oracle-19

_docker-test-%: TAG=$*
_docker-test-%:
docker run --rm --platform ${DOCKER_PLATFORMS} ${DOCKER_IMAGE}:${TAG} php --version

test-full: _docker-test-full
test-dg: _docker-test-dg
test-editor: _docker-test-editor
test-mongo: _docker-test-mongo
test-mssql: _docker-test-mssql
test-mysql: _docker-test-mysql
test-postgres: _docker-test-postgres
test-oracle-11: _docker-test-oracle-11
test-oracle-12: _docker-test-oracle-12
test-oracle-19: _docker-test-oracle-19

test-all: test-full test-dg test-editor test-mongo test-mssql test-mysql test-postgres test-oracle-11 test-oracle-12 test-oracle-19

_docker-run-%: TAG=$*
_docker-run-%:
docker run --rm -it -p ${DOCKER_RUN_PORT}:80 ${DOCKER_IMAGE}:${TAG}

run-full: _docker-run-full
run-dg: _docker-run-dg
run-editor: _docker-run-editor
run-mongo: _docker-run-mongo
run-mssql: _docker-run-mssql
run-mysql: _docker-run-mysql
run-postgres: _docker-run-postgres
run-oracle-11: _docker-run-oracle-11
run-oracle-12: _docker-run-oracle-12
run-oracle-19: _docker-run-oracle-19

update-versions:
##@ Build Variants

.PHONY: build-full
build-full: _docker-build-full ## Build the full (MySQL, PostgreSQL, SQLite, MongoDB) image

.PHONY: build-dg
build-dg: _docker-build-dg ## Build the adminer-custom image

.PHONY: build-editor
build-editor: _docker-build-editor ## Build the Adminer Editor image

.PHONY: build-mongo
build-mongo: _docker-build-mongo ## Build the MongoDB image

.PHONY: build-mssql
build-mssql: _docker-build-mssql ## Build the MS SQL Server image

.PHONY: build-mysql
build-mysql: _docker-build-mysql ## Build the MySQL image

.PHONY: build-postgres
build-postgres: _docker-build-postgres ## Build the PostgreSQL image

.PHONY: build-oracle-11
build-oracle-11: _docker-build-oracle-11 ## Build the Oracle 11 image

.PHONY: build-oracle-12
build-oracle-12: _docker-build-oracle-12 ## Build the Oracle 12 image

.PHONY: build-oracle-19
build-oracle-19: _docker-build-oracle-19 ## Build the Oracle 19 image

##@ Test Variants

.PHONY: test-full
test-full: _docker-test-full ## Test the full (MySQL, PostgreSQL, SQLite, MongoDB) image

.PHONY: test-dg
test-dg: _docker-test-dg ## Test the adminer-custom image

.PHONY: test-editor
test-editor: _docker-test-editor ## Test the Adminer Editor image

.PHONY: test-mongo
test-mongo: _docker-test-mongo ## Test the MongoDB image

.PHONY: test-mssql
test-mssql: _docker-test-mssql ## Test the MS SQL Server image

.PHONY: test-mysql
test-mysql: _docker-test-mysql ## Test the MySQL image

.PHONY: test-postgres
test-postgres: _docker-test-postgres ## Test the PostgreSQL image

.PHONY: test-oracle-11
test-oracle-11: _docker-test-oracle-11 ## Test the Oracle 11 image

.PHONY: test-oracle-12
test-oracle-12: _docker-test-oracle-12 ## Test the Oracle 12 image

.PHONY: test-oracle-19
test-oracle-19: _docker-test-oracle-19 ## Test the Oracle 19 image

##@ Run Variants

.PHONY: run-full
run-full: _docker-run-full ## Run the full (MySQL, PostgreSQL, SQLite, MongoDB) image on port 8000

.PHONY: run-dg
run-dg: _docker-run-dg ## Run the adminer-custom image on port 8000

.PHONY: run-editor
run-editor: _docker-run-editor ## Run the Adminer Editor image on port 8000

.PHONY: run-mongo
run-mongo: _docker-run-mongo ## Run the MongoDB image on port 8000

.PHONY: run-mssql
run-mssql: _docker-run-mssql ## Run the MS SQL Server image on port 8000

.PHONY: run-mysql
run-mysql: _docker-run-mysql ## Run the MySQL image on port 8000

.PHONY: run-postgres
run-postgres: _docker-run-postgres ## Run the PostgreSQL image on port 8000

.PHONY: run-oracle-11
run-oracle-11: _docker-run-oracle-11 ## Run the Oracle 11 image on port 8000

.PHONY: run-oracle-12
run-oracle-12: _docker-run-oracle-12 ## Run the Oracle 12 image on port 8000

.PHONY: run-oracle-19
run-oracle-19: _docker-run-oracle-19 ## Run the Oracle 19 image on port 8000

##@ Maintenance

.PHONY: update-versions
update-versions: ## Set ENV ADMINER_VERSION in every Dockerfile (ADMINER_VERSION=x, BSD sed)
find . -type f -name Dockerfile -exec sed -i '' 's/ENV ADMINER_VERSION=.*/ENV ADMINER_VERSION=${ADMINER_VERSION}/g' {} +
find . -type f -name Dockerfile -exec sed -i '' 's/ENV ADMINER_EDITOR_VERSION=.*/ENV ADMINER_EDITOR_VERSION=${ADMINER_VERSION}/g' {} +
Loading
Loading