{"id":51544131,"url":"https://github.com/devcavin/gatelog","last_synced_at":"2026-07-09T16:30:35.777Z","repository":{"id":314806702,"uuid":"885520474","full_name":"devcavin/gatelog","owner":"devcavin","description":"Gatelog: Digital Visitor Management System","archived":false,"fork":false,"pushed_at":"2026-07-01T15:18:08.000Z","size":165,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-01T17:13:04.810Z","etag":null,"topics":["docker","jwt","kotlin","postgresql","spring-boot","visitor-management-system"],"latest_commit_sha":null,"homepage":"","language":"Kotlin","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/devcavin.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-11-08T18:42:06.000Z","updated_at":"2026-07-01T15:18:17.000Z","dependencies_parsed_at":"2025-09-14T23:31:38.321Z","dependency_job_id":"a83e31b9-124a-4c16-8679-a022820764bc","html_url":"https://github.com/devcavin/gatelog","commit_stats":null,"previous_names":["killercavin/spring-security-basics","devcavin/spring-security-basics","devcavin/gatelog"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/devcavin/gatelog","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devcavin%2Fgatelog","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devcavin%2Fgatelog/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devcavin%2Fgatelog/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devcavin%2Fgatelog/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/devcavin","download_url":"https://codeload.github.com/devcavin/gatelog/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devcavin%2Fgatelog/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35306715,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-09T02:00:07.329Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["docker","jwt","kotlin","postgresql","spring-boot","visitor-management-system"],"created_at":"2026-07-09T16:30:30.192Z","updated_at":"2026-07-09T16:30:35.771Z","avatar_url":"https://github.com/devcavin.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Gatelog - Digital Visitor Management System\n\n\u003e A production-grade visitor management system built to replace paper logbooks with a fast, searchable, and accountable web application.\n\n[//]: # (![CI]\u0026#40;https://github.com/devcavin/gatelog/actions/workflows/ci.yml/badge.svg\u0026#41;)\n\n[//]: # (![License]\u0026#40;https://img.shields.io/badge/license-MIT-blue.svg\u0026#41;)\n\n[//]: # (![Status]\u0026#40;https://img.shields.io/badge/status-active%20development-orange\u0026#41;)\n\n---\n\n## What is Gatelog?\n\nGatelog is a digital visitor management system designed for any single-site premises, a corporate office, a clinic, a school, or a residential estate. It replaces paper-based visitor logbooks with a structured, role-aware, and cloud-deployable web application.\n\nThe project is built to demonstrate end-to-end product engineering: system design, backend API development, cloud deployment, CI/CD, and security-conscious development practices.\n\n---\n\n## Live Demo\n- Frontend - [htts://gatelogapp.vercel.app](htts://gatelogapp.vercel.app)\n\n---\n\n## Stack\n\n| Layer      | Technology                        |\n|------------|-----------------------------------|\n| Backend    | Kotlin + Spring Boot 3            |\n| Database   | PostgreSQL (Supabase)             |\n| Auth       | Spring Security + JWT             |\n| ORM        | Spring Data JPA / Hibernate       |\n| Migrations | Flyway                            |\n| Docs       | SpringDoc OpenAPI / Swagger UI    |\n| CI/CD      | GitHub Actions + GHCR             |\n| Deployment | Render (compute) + Supabase (db)  |\n\n---\n\n## Architecture\n\n```\n┌─────────────────────────────────────────┐\n│              React Frontend             │  ← Phase 2\n│         (TypeScript + Vite)             │\n└────────────────────┬────────────────────┘\n                     │ HTTPS / REST\n┌────────────────────▼────────────────────┐\n│           Spring Boot Backend           │\n│                                         │\n│  ┌─────────────┐   ┌─────────────────┐  │\n│  │ Controllers │   │ Security Filter │  │\n│  └──────┬──────┘   └────────┬────────┘  │\n│         │                   │ JWT        │\n│  ┌──────▼───────────────────▼────────┐  │\n│  │           Service Layer           │  │\n│  └──────────────────┬────────────────┘  │\n│                     │                   │\n│  ┌──────────────────▼────────────────┐  │\n│  │       Spring Data JPA / Flyway    │  │\n│  └──────────────────┬────────────────┘  │\n└─────────────────────┼───────────────────┘\n                      │\n┌─────────────────────▼───────────────────┐\n│         PostgreSQL (Supabase)           │\n└─────────────────────────────────────────┘\n```\n\n---\n\n## Data Model\n\n```\nroles ──────────────────────────► users\nvisit_statuses ─────────────────► visitors\nsites ──────────────────────────► zones\n                                  users\n                                  visitors\nzones ──────────────────────────► visitors (nullable)\nusers ──────────────────────────► visitors (created_by)\n                                  refresh_tokens\n```\n\nAll primary keys are UUID. Enums are replaced with lookup tables (`roles`, `visit_statuses`) for clean migrations and audit flexibility.\n\n---\n\n## Project Structure\n\n```\ngatelog/\n├── backend/\n│   ├── src/main/kotlin/io/github/devcavin/backend/\n│   │   ├── common/exception/      # domain exception hierarchy\n│   │   ├── config/                # security, CORS config\n│   │   ├── domain/\n│   │   │   ├── model/             # JPA entities\n│   │   │   └── repository/        # Spring Data repositories\n│   │   ├── security/              # JWT provider, filter, UserDetails\n│   │   ├── service/               # business logic\n│   │   └── web/\n│   │       ├── controller/        # REST controllers\n│   │       ├── dto/               # request/response DTOs\n│   │       └── error/             # global exception handler\n│   ├── src/main/resources/\n│   │   ├── db/migration/          # Flyway migrations v1–v7\n│   │   ├── application.yaml       # shared config (env var placeholders)\n│   │   └── application-local.yaml # local dev overrides (gitignored)\n│   ├── Dockerfile                 # multi-stage build\n│   └── compose.yaml               # local Postgres via Docker\n├── .github/workflows/\n│   └── ci.yml                     # test → build image → push to GHCR\n└── README.md\n```\n\n---\n\n## API Endpoints\n\n### Auth — `/api/auth`\n\n| Method | Endpoint          | Auth     | Description                  |\n|--------|-------------------|----------|------------------------------|\n| POST   | `/login`          | Public   | Login, returns JWT pair      |\n| POST   | `/refresh`        | Public   | Rotate refresh token         |\n| POST   | `/logout`         | Public   | Invalidate refresh token     |\n\n### Users — `/api/users`\n\n| Method | Endpoint | Auth                      | Description          |\n|--------|----------|---------------------------|----------------------|\n| POST   | `/`      | SUPER_ADMIN, MANAGER      | Create a user        |\n\n\u003e Managers can only create Staff accounts scoped to their own site.\n\u003e Super Admin can create any role at any site.\n\n### Visitors — `/api/visitors` _(in progress)_\n\n| Method | Endpoint              | Auth                       | Description                    |\n|--------|-----------------------|----------------------------|--------------------------------|\n| POST   | `/`                   | All roles                  | Register a new visitor         |\n| GET    | `/{id}`               | All roles                  | Get visitor by ID              |\n| PATCH  | `/{id}/checkout`      | All roles                  | Check out a visitor            |\n| GET    | `/`                   | All roles                  | Search visitors (paginated)    |\n| GET    | `/returning`          | All roles                  | Returning visitor phone lookup |\n\n---\n\n## Role-Based Access Control\n\n| Role        | Capabilities                                                          |\n|-------------|-----------------------------------------------------------------------|\n| SUPER_ADMIN | Full access, users, config, all analytics, all visitor records        |\n| MANAGER     | Reports, analytics, visitor records, create Staff users at own site   |\n| STAFF       | Register visitors, check in/out, view active visitors, search history |\n\nRole enforcement happens at two layers: `@PreAuthorize` on controllers (HTTP level) and explicit business rules in the service layer (domain level).\n\n---\n\n## Running Locally\n\n**Prerequisites:** Docker, JDK 21, Git\n\n```bash\n# 1. clone\ngit clone https://github.com/devcavin/gatelog.git\ncd gatelog/backend\n\n# 2. start postgres\ndocker compose up -d\n\n# 3. run the app (local profile auto-activates)\nSPRING_PROFILES_ACTIVE=local \\\nDB_URL=jdbc:postgresql://localhost:5432/gatelog \\\nDB_USERNAME=postgres \\\nDB_PASSWORD=secret \\\nJWT_SECRET=local-dev-secret-key-must-be-at-least-256-bits-long-for-hs256 \\\nCORS_ALLOWED_ORIGINS=http://localhost:5173 \\\n./gradlew bootRun\n\n# 4. open swagger\nopen http://localhost:8080/swagger-ui/index.html\n```\n\nFlyway runs all migrations automatically on startup. The database is seeded with roles, visit statuses, a default site, and a Super Admin account.\n\n---\n\n## Environment Variables\n\n| Variable                  | Description                                | Required |\n|---------------------------|--------------------------------------------|----------|\n| `DB_URL`                  | JDBC connection URL                        | Yes      |\n| `DB_USERNAME`             | Database username                          | Yes      |\n| `DB_PASSWORD`             | Database password                          | Yes      |\n| `JWT_SECRET`              | HS256 signing key (min 256 bits)           | Yes      |\n| `JWT_ACCESS_EXPIRY_MS`    | Access token expiry in ms (default 900000) | No       |\n| `JWT_REFRESH_EXPIRY_DAYS` | Refresh token expiry in days (default 7)   | No       |\n| `CORS_ALLOWED_ORIGINS`    | Allowed frontend origins                   | Yes      |\n| `SPRING_PROFILES_ACTIVE`  | Active Spring profile                      | No       |\n\n---\n\n## CI/CD\n\nEvery push to `main` that touches `backend/**`:\n\n1. **Test** - runs the full test suite with Testcontainers (real Postgres)\n2. **Build image** - multi-stage Docker build, pushed to GHCR with SHA tag and `latest`\n3. **Deploy image** - deploying the build image to render\n\n```\nghcr.io/devcavin/gatelog-backend:latest\nghcr.io/devcavin/gatelog-backend:\u003cshort-sha\u003e\n```\n\n---\n\n## Roadmap\n\n### Phase 1 - Core System _(in progress)_\n- [x] Database schema and Flyway migrations\n- [x] JWT authentication with refresh token rotation\n- [x] Role-based access control (Super Admin, Manager, Staff)\n- [x] User registration endpoint with role enforcement\n- [x] CI pipeline with GitHub Actions\n- [x] Visitor registration and check-in/check-out\n- [x] Real-time dashboard endpoints\n- [x] Visitor search with dynamic filters\n- [x] CSV export\n- [ ] React frontend(in progress)\n\n### Phase 2 - Intelligence Layer _(planned)_\n- [ ] SMS OTP verification (Africa's Talking / Twilio)\n- [ ] Analytics dashboard\n- [ ] Zone routing and host notifications\n- [ ] PDF export\n- [ ] Scheduled report delivery\n- [ ] Kubernetes deployment with Helm\n- [ ] Observability with Prometheus and Grafana\n\n---\n\n## Architecture Decisions\n\n[//]: # (**Why Kotlin over Java?** Kotlin's null safety, data classes, and expression-based syntax produce cleaner, more readable code with less boilerplate. Full Spring Boot compatibility means no ecosystem tradeoffs.)\n\n**Why lookup tables over enums?** PostgreSQL enums cannot have values removed without recreating the type, making migrations fragile. Lookup tables (`roles`, `visit_statuses`) keep migrations clean and make audit queries straightforward.\n\n**Why no offline mode?** Cloud hosting is a deliberate architectural choice. The system trades offline capability for real-time data availability, automated backups, and searchability, none of which paper can provide.\n\n**Why layered monolith over Spring Modulith?** For a single-developer MVP, a clean layered monolith ships faster and is more familiar to most engineering teams reviewing the code. Spring Modulith is the right next step if the domain grows and team size increases, that migration path is documented and the package structure supports it without a full rewrite.\n\n---\n\n[//]: # (## License)\n\n[//]: # ()\n[//]: # (MIT — see [LICENSE]\u0026#40;LICENSE\u0026#41;)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevcavin%2Fgatelog","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdevcavin%2Fgatelog","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevcavin%2Fgatelog/lists"}