Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
dd88ca2
chore: initialize Rails application and development environment
antonioneto1 Sep 3, 2026
2922cfa
feat: add user model with roles on top of native authentication
antonioneto1 Sep 3, 2026
745dfc1
feat: add registration, profiles and role-based authorization
antonioneto1 Sep 3, 2026
f4fda27
feat: let each user pick their interface language
antonioneto1 Sep 3, 2026
112774d
feat: add admin user management with search, filtering and pagination
antonioneto1 Sep 3, 2026
a41a540
feat: stream live dashboard counters over Solid Cable
antonioneto1 Sep 3, 2026
af2698e
fix: make missing translations fail the suite, and fix the ones hiding
antonioneto1 Sep 3, 2026
fcec899
feat: add avatars, and cover the password reset flow
antonioneto1 Sep 3, 2026
73f3c8f
feat: import users asynchronously from CSV and XLSX
antonioneto1 Sep 3, 2026
70fc7dd
feat: sweep the application for security, vector by vector
antonioneto1 Sep 4, 2026
dffa9e9
feat: make the application deployable, and prove the image boots
antonioneto1 Sep 4, 2026
cfcd264
fix: give the password reset screens the same design and languages
antonioneto1 Sep 4, 2026
2a17c34
test: walk the three journeys in a browser, and prove the live updates
antonioneto1 Sep 4, 2026
6d90113
feat: fold the language flags into a single menu
antonioneto1 Sep 4, 2026
c5dd87c
fix: two defects the tests were not looking for
antonioneto1 Sep 4, 2026
f142f99
ci: run the real pipeline, and check accessibility instead of claimin…
antonioneto1 Sep 4, 2026
c10d32d
feat: invite the people an import creates
antonioneto1 Sep 4, 2026
fdc8a81
perf: make the search use an index instead of reading every row
antonioneto1 Sep 4, 2026
72c556b
feat: keep a record of what administrators did
antonioneto1 Sep 4, 2026
c081a39
feat: add a JSON API, documented by the specs that exercise it
antonioneto1 Sep 4, 2026
12174fb
feat: let a deployment put a password in front of the API docs
antonioneto1 Sep 4, 2026
f4a30e7
chore: one script per action, the way the reference project does it
antonioneto1 Sep 4, 2026
30afd0b
fix: put the error next to the field, and a heading on every page
antonioneto1 Sep 4, 2026
e159652
docs: write the README the submission is judged by
antonioneto1 Sep 4, 2026
19993e0
docs: quote numbers that survive being run again
antonioneto1 Sep 4, 2026
dfd599b
fix: keep the working documents out of the production image
antonioneto1 Sep 4, 2026
f6d2154
ci: run the pipeline on every branch, not only the default one
antonioneto1 Sep 4, 2026
144245d
ci: give the checkout to the user the container runs as
antonioneto1 Sep 4, 2026
ee47464
ci: bring the inherited CodeQL workflow up to a version that runs
antonioneto1 Sep 4, 2026
03df955
ci: prepare the databases before waiting for the application
antonioneto1 Sep 4, 2026
85e3378
ci: let the runner keep writing to the workspace it checked out
antonioneto1 Sep 4, 2026
9e6ff12
ci: shard the suite across workers in the pipeline too
antonioneto1 Sep 4, 2026
52dba24
docs: say that the pipeline shards the suite, and record the flake
antonioneto1 Sep 4, 2026
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
72 changes: 72 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# See https://docs.docker.com/engine/reference/builder/#dockerignore-file for more about ignoring files.

# Ignore git directory.
/.git/
/.gitignore

# Ignore bundler config.
/.bundle

# Ignore all environment files.
/.env*

# Ignore all default key files.
/config/master.key
/config/credentials/*.key

# Ignore all logfiles and tempfiles.
/log/*
/tmp/*
!/log/.keep
!/tmp/.keep

# Ignore pidfiles, but keep the directory.
/tmp/pids/*
!/tmp/pids/.keep

# Ignore storage (uploaded files in development and any SQLite databases).
/storage/*
!/storage/.keep
/tmp/storage/*
!/tmp/storage/.keep

# Ignore assets.
/node_modules/
/app/assets/builds/*
!/app/assets/builds/.keep
/public/assets

# Ignore CI service files.
/.github

# Ignore Kamal files.
/config/deploy*.yml
/.kamal

# Ignore development files
/.devcontainer

# Ignore Docker-related files
/.dockerignore
/Dockerfile*

# Ignore the test suite and coverage output: they are not needed in the
# production image and only make it larger.
/spec
/coverage
/.rspec_status

# Ignore host-side operational scripts; they drive Docker from outside.
/devops

# Ignore the working documents that live beside the repository but are not part
# of it. They are untracked, so a fresh clone has none of them -- but a build
# from the machine they were written on would copy them straight into the image
# somebody else pulls.
/PLANO_TESTE_FULLSTACK_UMANNI.md
/PENDENCIAS.md
/CREDENCIAIS_LOCAIS.txt

# The README screenshots are for people reading the repository, not for the
# running application.
/docs
13 changes: 13 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Copy to .env (bin/setup does it for you). These values are development-only;
# production configuration is supplied by Kamal secrets, never by this file.

# ── PostgreSQL ───────────────────────────────────────────────────────────────
POSTGRES_USER=user_management
POSTGRES_PASSWORD=development_only
POSTGRES_DB=user_management_development
TEST_POSTGRES_DB=user_management_test

# ── Application ──────────────────────────────────────────────────────────────
# Host port for the web server.
WEB_PORT=3000
RAILS_MAX_THREADS=5
9 changes: 9 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# See https://git-scm.com/docs/gitattributes for more about git attribute files.

# Mark the database schema as having been generated.
db/schema.rb linguist-generated

# Mark any vendored files as having been vendored.
vendor/* linguist-vendored
config/credentials/*.yml.enc diff=rails_credentials
config/credentials.yml.enc diff=rails_credentials
12 changes: 12 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
version: 2
updates:
- package-ecosystem: bundler
directory: "/"
schedule:
interval: weekly
open-pull-requests-limit: 10
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: weekly
open-pull-requests-limit: 10
73 changes: 73 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# One job, running the same pipeline a person runs locally: bin/ci inside the
# same container the application is developed in. A workflow that installs its
# own Ruby and its own PostgreSQL would be a second definition of the
# environment, free to drift from the one in the repository.
name: CI

on:
# Every branch, not only the default one: work in progress on a branch is
# exactly when the pipeline is worth having, and a pull request from a fork
# runs only after a maintainer approves it -- which is too late to be useful
# to whoever pushed.
push:
pull_request:

# A push and a pull request on the same branch would otherwise start two
# identical runs, and every new push would leave the previous one grinding away
# on code nobody is looking at any more.
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
ci:
name: Style, security and tests
runs-on: ubuntu-latest
timeout-minutes: 25

steps:
- name: Checkout code
uses: actions/checkout@v6

- name: Share the checkout with the container's user
# The development image runs as uid 1000 -- the common host uid, which
# is what keeps bind-mounted files writable from both sides on a
# laptop. A runner checks the repository out as a different user, and
# Rails cannot so much as create tmp/cache in a directory it does not
# own, so the web container exits before it can answer a health check.
#
# Handing the tree over outright is too much, though: it locked the
# runner out of its own workspace, and the next step could not create
# .env. The container user owns the tree, the runner's group keeps
# write access, and both sides can write -- which is what a bind mount
# shared between two users needs.
run: |
sudo chown -R 1000:"$(id -g)" .
sudo chmod -R g+rwX .

- name: Cache the Docker layers
uses: docker/setup-buildx-action@v3

# The same script the README tells a person to run, rather than a
# separate sequence of docker commands that could quietly stop matching
# it: it writes .env, builds the image, creates and migrates the four
# databases, and waits for every service to report healthy. Without the
# databases the health check fails -- /up goes through the cache store,
# which has a database of its own.
- name: Set the environment up, exactly as the README says
run: devops/app/setup.sh --no-seed

- name: Run the pipeline
run: bin/ci

- name: Keep the coverage report
if: always()
uses: actions/upload-artifact@v4
with:
name: coverage
path: coverage/
retention-days: 7

- name: Show the logs when something fails
if: failure()
run: docker compose logs --tail 200
63 changes: 25 additions & 38 deletions .github/workflows/codeql-analysis.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# CodeQL, as it comes with the repository -- brought up to date so it can
# actually run. The workflow shipped pinned to github/codeql-action@v1, which
# GitHub retired in January 2023 and which now refuses to start, and it asked
# for no permissions, so the default read-only token could not write findings:
# "Resource not accessible by integration".
name: "Code scanning - action"

on:
Expand All @@ -8,44 +13,26 @@ on:

jobs:
CodeQL-Build:

runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
fetch-depth: 2

# If this run was triggered by a pull request event, then checkout
# the head of the pull request instead of the merge commit.
- run: git checkout HEAD^2
if: ${{ github.event_name == 'pull_request' }}

# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
# Override language selection by uncommenting this and choosing your languages
# with:
# languages: go, javascript, csharp, python, cpp, java

# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# The default GITHUB_TOKEN is read-only. CodeQL uploads what it finds, so
# it needs to write security events -- and nothing else.
permissions:
actions: read
contents: read
security-events: write

# ℹ️ Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl

# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language

#- run: |
# make bootstrap
# make release

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1
steps:
- name: Checkout repository
uses: actions/checkout@v6

# The languages are named rather than guessed: this is a Rails
# application with a handful of Stimulus controllers, and nothing
# compiled, so there is no Autobuild step to run.
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ruby, javascript-typescript

- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
43 changes: 43 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# See https://help.github.com/articles/ignoring-files for more about ignoring files.
#
# Temporary files generated by your text editor or operating system
# belong in git's global ignore instead:
# `$XDG_CONFIG_HOME/git/ignore` or `~/.config/git/ignore`

# Ignore bundler config.
/.bundle

# Ignore all environment files, but keep the documented template.
/.env*
!/.env.example

# Ignore all logfiles and tempfiles.
/log/*
/tmp/*
!/log/.keep
!/tmp/.keep

# Ignore pidfiles, but keep the directory.
/tmp/pids/*
!/tmp/pids/
!/tmp/pids/.keep

# Ignore storage (uploaded files in development and any SQLite databases).
/storage/*
!/storage/.keep
/tmp/storage/*
!/tmp/storage/
!/tmp/storage/.keep

/public/assets

# Ignore key files for decrypting credentials and more.
/config/*.key


# Ignore coverage reports and RSpec run state.
/coverage
/.rspec_status

/app/assets/builds/*
!/app/assets/builds/.keep
17 changes: 17 additions & 0 deletions .kamal/secrets
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Read by Kamal at deploy time and passed to the containers. Nothing here is a
# secret itself: each line names where the value comes from, and the values
# stay in the environment of whoever runs the deploy (or in a password
# manager, via `kamal secrets fetch`).
#
# export KAMAL_REGISTRY_PASSWORD=...
# export POSTGRES_PASSWORD=...
#
KAMAL_REGISTRY_PASSWORD=$KAMAL_REGISTRY_PASSWORD

# config/master.key is not in the repository; the deploying machine has it.
RAILS_MASTER_KEY=$(cat config/master.key)

POSTGRES_PASSWORD=$POSTGRES_PASSWORD

# Only needed on the first deploy, together with SEED_ADMIN_EMAIL:
# SEED_ADMIN_PASSWORD=$SEED_ADMIN_PASSWORD
1 change: 1 addition & 0 deletions .rspec
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--require spec_helper
Loading