Merge branch 'main' into codex/0.1-kanban-foundation/06-ticket-creation-and-backlog

This commit is contained in:
Nico Schroeder
2026-03-30 19:57:46 +02:00
30 changed files with 331424 additions and 78 deletions
+49
View File
@@ -0,0 +1,49 @@
# Include any files or directories that you don't want to be copied to your
# container here (e.g., local build artifacts, temporary files, etc.).
#
# For more help, visit the .dockerignore file reference guide at
# https://docs.docker.com/go/build-context-dockerignore/
**/.classpath
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.gitattributes
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/.next
**/.cache
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/docker-compose*
**/compose.y*ml
**/compose.*.y*ml
!**/composer.json
!**/composer.lock
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
vendor
**/.DS_Store
.editorconfig
.env.example
.env.mariadb
.env.mariadb.example
.env.production
LICENSE
README.md
# Ignore development-related files and directories
# For development environment, we will use mount bind to mount the source code to the container
# So we don't need to copy the source code to the container for development
tests/
phpunit.xml
phpunit.xml.dist
+19 -50
View File
@@ -1,65 +1,34 @@
APP_NAME=Laravel APP_NAME=kanbangit
APP_ENV=local APP_ENV=local
APP_KEY= APP_KEY=
APP_DEBUG=true APP_DEBUG=true
APP_TIMEZONE=Europe/Berlin
APP_URL=http://localhost APP_URL=http://localhost
API_KEY=
APP_LOCALE=en APP_LOCALE=en
APP_FALLBACK_LOCALE=en APP_FALLBACK_LOCALE=en
APP_FAKER_LOCALE=en_US APP_FAKER_LOCALE=en_US
APP_MAINTENANCE_DRIVER=file LOG_STACK=daily
# APP_MAINTENANCE_STORE=database
# PHP_CLI_SERVER_WORKERS=4 DB_CONNECTION=mariadb
DB_HOST=kanbangit-db
DB_PORT=3306
DB_DATABASE=kanbangit
DB_USERNAME=
DB_PASSWORD=
BCRYPT_ROUNDS=12 #Default
MAIL_MAILER=smtp
LOG_CHANNEL=stack MAIL_HOST=mail.example.de
LOG_STACK=single MAIL_PORT=587
LOG_DEPRECATIONS_CHANNEL=null MAIL_USERNAME=no-reply@example.com
LOG_LEVEL=debug MAIL_PASSWORD=
MAIL_ENCRYPTION=tls
DB_CONNECTION=sqlite MAIL_FROM_ADDRESS=no-reply@example.com
# DB_HOST=127.0.0.1
# DB_PORT=3306
# DB_DATABASE=laravel
# DB_USERNAME=root
# DB_PASSWORD=
SESSION_DRIVER=database
SESSION_LIFETIME=120
SESSION_ENCRYPT=false
SESSION_PATH=/
SESSION_DOMAIN=null
BROADCAST_CONNECTION=log
FILESYSTEM_DISK=local
QUEUE_CONNECTION=database
CACHE_STORE=database
# CACHE_PREFIX=
MEMCACHED_HOST=127.0.0.1
REDIS_CLIENT=phpredis
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=null
REDIS_PORT=6379
MAIL_MAILER=log
MAIL_SCHEME=null
MAIL_HOST=127.0.0.1
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_FROM_ADDRESS="hello@example.com"
MAIL_FROM_NAME="${APP_NAME}" MAIL_FROM_NAME="${APP_NAME}"
AWS_ACCESS_KEY_ID= FILESYSTEM_DISK=public
AWS_SECRET_ACCESS_KEY=
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=
AWS_USE_PATH_STYLE_ENDPOINT=false
VITE_APP_NAME="${APP_NAME}" VITE_APP_NAME="${APP_NAME}"
+4
View File
@@ -0,0 +1,4 @@
MARIADB_DATABASE=kanbangit
MARIADB_USER=kanbangit
MARIADB_PASSWORD=
MARIADB_ROOT_PASSWORD=
+1
View File
@@ -13,6 +13,7 @@
.DS_Store .DS_Store
.env .env
.env.backup .env.backup
.env.mariadb
.env.production .env.production
.phpactor.json .phpactor.json
.phpunit.result.cache .phpunit.result.cache
@@ -9,6 +9,7 @@ use App\Models\BoardColumn;
use App\Models\Project; use App\Models\Project;
use Illuminate\Http\RedirectResponse; use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Inertia\Inertia; use Inertia\Inertia;
@@ -42,12 +43,13 @@ class ProjectBoardSettingsController extends Controller
$this->projectPermissionService->userCanManageProjectAccess($request->user(), $project), $this->projectPermissionService->userCanManageProjectAccess($request->user(), $project),
403, 403,
); );
$validated = $request->validated();
$desiredPosition = $request->position() ?? $project->boardColumns()->count() + 1; $desiredPosition = Arr::get($validated, 'position') ?? $project->boardColumns()->count() + 1;
$boardColumn = DB::transaction(function () use ($project, $request, $desiredPosition): BoardColumn { $boardColumn = DB::transaction(function () use ($project, $validated, $desiredPosition): BoardColumn {
$boardColumn = $project->boardColumns()->create([ $boardColumn = $project->boardColumns()->create([
'name' => $request->validated('name'), 'name' => Arr::get($validated, 'name'),
'position' => $project->boardColumns()->count() + 1, 'position' => $project->boardColumns()->count() + 1,
]); ]);
@@ -69,13 +71,14 @@ class ProjectBoardSettingsController extends Controller
$this->projectPermissionService->userCanManageProjectAccess($request->user(), $project), $this->projectPermissionService->userCanManageProjectAccess($request->user(), $project),
403, 403,
); );
$validated = $request->validated();
DB::transaction(function () use ($boardColumn, $project, $request): void { DB::transaction(function () use ($boardColumn, $project, $validated): void {
$boardColumn->update([ $boardColumn->update([
'name' => $request->validated('name'), 'name' => Arr::get($validated, 'name'),
]); ]);
$this->reorderColumns($project, $boardColumn, $request->position()); $this->reorderColumns($project, $boardColumn, Arr::get($validated, 'position'));
}); });
return to_route('projects.settings.board', $project) return to_route('projects.settings.board', $project)
@@ -12,7 +12,7 @@ class UpdateUserAdminStatusRequest extends FormRequest
*/ */
public function authorize(): bool public function authorize(): bool
{ {
return $this->user()?->is_admin === true; return $this->user()?->can('access-admin') ?? false;
} }
/** /**
@@ -27,15 +27,4 @@ class StoreBoardColumnRequest extends FormRequest
'position' => ['nullable', 'integer', 'min:1'], 'position' => ['nullable', 'integer', 'min:1'],
]; ];
} }
public function position(): ?int
{
$position = $this->validated('position');
if ($position === null) {
return null;
}
return (int) $position;
}
} }
@@ -27,9 +27,4 @@ class UpdateBoardColumnRequest extends FormRequest
'position' => ['required', 'integer', 'min:1'], 'position' => ['required', 'integer', 'min:1'],
]; ];
} }
public function position(): int
{
return (int) $this->validated('position');
}
} }
+69
View File
@@ -0,0 +1,69 @@
services:
web:
container_name: kanbangit-web
build:
context: .
dockerfile: ./docker/nginx/Dockerfile
restart: unless-stopped
ports:
- "8080:80"
volumes:
- kanbangit-storage:/var/www/storage:ro
- kanbangit-public-assets:/var/www/public/build:ro
env_file:
- .env.production
networks:
- kanbangit-web
depends_on:
php-fpm:
condition: service_healthy
php-fpm:
container_name: kanbangit-php-fpm
build:
context: .
dockerfile: ./docker/php-fpm/Dockerfile
target: production
restart: unless-stopped
volumes:
- kanbangit-storage:/var/www/storage
- kanbangit-public-assets:/var/www/public/build
env_file:
- .env.production
networks:
- kanbangit-web
- kanbangit-db
healthcheck:
test: ["CMD-SHELL", "php-fpm-healthcheck || exit 1"]
interval: 10s
timeout: 5s
retries: 3
depends_on:
mariadb:
condition: service_healthy
mariadb:
container_name: kanbangit-db
image: mariadb:11.4
restart: unless-stopped
env_file:
- .env.mariadb
command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
volumes:
- mariadb-data-production:/var/lib/mysql
networks:
- kanbangit-db
healthcheck:
test: [ "CMD", "healthcheck.sh", "--connect", "--innodb_initialized" ]
start_period: 10s
interval: 10s
timeout: 5s
retries: 3
networks:
kanbangit-db:
kanbangit-web:
volumes:
mariadb-data-production:
kanbangit-storage:
kanbangit-public-assets:
+20
View File
@@ -0,0 +1,20 @@
FROM php:8.4-cli-bookworm AS builder
RUN apt-get update && apt-get install -y --no-install-recommends \
curl ca-certificates git unzip \
&& rm -rf /var/lib/apt/lists/*
RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
&& apt-get update && apt-get install -y --no-install-recommends nodejs \
&& rm -rf /var/lib/apt/lists/*
RUN curl -sS https://getcomposer.org/installer | php -- \
--install-dir=/usr/local/bin --filename=composer
WORKDIR /var/www
COPY . /var/www
RUN composer install --no-dev --prefer-dist --no-interaction --no-progress --optimize-autoloader
RUN npm ci && npm run build
FROM nginx:alpine
COPY ./docker/nginx/nginx.conf /etc/nginx/nginx.conf
COPY --from=builder /var/www/public /var/www/public
WORKDIR /var/www/public
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
+33
View File
@@ -0,0 +1,33 @@
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
client_max_body_size 100m;
server {
listen 80;
server_name localhost;
root /var/www/public;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ^~ /storage/ {
alias /var/www/storage/app/public/;
try_files $uri =404;
access_log off;
expires 7d;
add_header Cache-Control "public";
}
location ~ \.php$ {
fastcgi_pass php-fpm:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}
}
+66
View File
@@ -0,0 +1,66 @@
FROM php:8.4-fpm AS builder
RUN apt-get update && apt-get install -y --no-install-recommends \
curl \
unzip \
libpq-dev \
libonig-dev \
libssl-dev \
libxml2-dev \
libcurl4-openssl-dev \
libicu-dev \
libzip-dev \
libmagickwand-dev \
libpng-dev \
libjpeg-dev \
libfreetype6-dev \
&& docker-php-ext-install -j$(nproc) \
pdo_mysql \
pdo_pgsql \
pgsql \
opcache \
intl \
zip \
bcmath \
soap \
&& docker-php-ext-configure gd --with-jpeg --with-freetype \
&& docker-php-ext-install -j$(nproc) gd \
&& pecl install imagick \
&& docker-php-ext-enable imagick \
&& apt-get autoremove -y && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
WORKDIR /var/www
COPY . /var/www
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer \
&& composer install --no-dev --optimize-autoloader --no-interaction --no-progress --prefer-dist
FROM php:8.4-fpm AS production
RUN apt-get update && apt-get install -y --no-install-recommends \
libpq-dev \
libicu-dev \
libzip-dev \
libfcgi-bin \
procps \
libmagickwand-dev \
&& apt-get autoremove -y && apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
RUN curl -o /usr/local/bin/php-fpm-healthcheck \
https://raw.githubusercontent.com/renatomefi/php-fpm-healthcheck/master/php-fpm-healthcheck \
&& chmod +x /usr/local/bin/php-fpm-healthcheck
COPY ./docker/php-fpm/entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/entrypoint.sh
COPY ./storage /var/www/storage-init
COPY --from=builder /usr/local/lib/php/extensions/ /usr/local/lib/php/extensions/
COPY --from=builder /usr/local/etc/php/conf.d/ /usr/local/etc/php/conf.d/
COPY --from=builder /usr/local/bin/docker-php-ext-* /usr/local/bin/
RUN mv "$PHP_INI_DIR/php.ini-production" "$PHP_INI_DIR/php.ini"
RUN printf '%s\n' \
'[global]' \
'daemonize = no' \
'' \
'[www]' \
'pm.status_path = /status' \
> /usr/local/etc/php-fpm.d/zz-docker.conf
COPY --from=builder /var/www /var/www
WORKDIR /var/www
RUN chown -R www-data:www-data /var/www
USER www-data
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
EXPOSE 9000
CMD ["php-fpm"]
+11
View File
@@ -0,0 +1,11 @@
#!/bin/sh
set -e
if [ ! "$(ls -A /var/www/storage)" ]; then
echo "Initializing storage directory..."
cp -R /var/www/storage-init/. /var/www/storage
chown -R www-data:www-data /var/www/storage
fi
rm -rf /var/www/storage-init
php artisan config:cache
php artisan route:cache
exec "$@"
+1
View File
@@ -15,6 +15,7 @@ The product centers around projects. Each project owns its own board configurati
- [Product Spec](product-spec.md) describes expected product behavior, user-visible rules, and scope boundaries. - [Product Spec](product-spec.md) describes expected product behavior, user-visible rules, and scope boundaries.
- [Domain Model](domain-model.md) defines the canonical domain concepts, relationships, and invariants that future database tables, Eloquent models, policies, and frontend types should follow. - [Domain Model](domain-model.md) defines the canonical domain concepts, relationships, and invariants that future database tables, Eloquent models, policies, and frontend types should follow.
- [Architecture Roadmap](architecture-roadmap.md) captures the planned architecture direction, permission strategy, integration boundaries, and staged implementation intent. - [Architecture Roadmap](architecture-roadmap.md) captures the planned architecture direction, permission strategy, integration boundaries, and staged implementation intent.
- [GitHub Integration Plan](github-integration-plan.md) captures the first planned GitHub-specific integration strategy for release `0.3`.
- [Release Task Breakdown](releases/README.md) splits the planned work into small ordered implementation tickets grouped by release. - [Release Task Breakdown](releases/README.md) splits the planned work into small ordered implementation tickets grouped by release.
## Glossary ## Glossary
File diff suppressed because one or more lines are too long
+107
View File
@@ -0,0 +1,107 @@
# GitHub Integration Plan
## Purpose
This document describes the intended first GitHub integration approach for KanbanGit release `0.3`.
The goal is to add GitHub as the second supported Git provider without redesigning the provider-neutral repository, branch, and pull request flows already introduced for Gitea.
## Source Material
- Primary API source: `docs/gitApiDocs/api.github.com.json`
- Primary target API: GitHub REST v3 on `https://api.github.com`
## Release Direction
Release `0.3` should deliver GitHub Cloud support through the existing per-user Git connection model.
Key decisions:
- The first GitHub auth mode is a user-managed token connection.
- GitHub Cloud uses a fixed API base URL instead of a user-entered instance URL.
- Connection validation should confirm repository read access.
- Authenticated user metadata from `GET /user` is useful for display, but it should not be the only success criterion if repository access can already be verified.
- The provider abstraction must remain the boundary between ticket or project logic and GitHub-specific HTTP details.
## Required API Surface for v0.3
The release should be planned around these endpoints from `api.github.com`:
- `GET /user`
- `GET /user/repos`
- `GET /repos/{owner}/{repo}`
- `GET /repos/{owner}/{repo}/branches`
- `GET /repos/{owner}/{repo}/pulls`
These endpoints are sufficient for the current KanbanGit feature set:
- storing a user Git connection
- discovering repositories the user can access
- linking repositories to projects
- matching branches to tickets by ticket key
- matching pull requests to tickets by source branch name
## Provider-Neutral Data Mapping
The GitHub provider should map its responses into the existing provider-neutral contracts already used by Gitea integration.
### Authenticated user
- `id` -> `provider_user_id`
- `login` -> `account_login`
- `name` -> `account_name`
### Repository
- `id` -> `provider_repository_id`
- `owner.login` -> `owner_name`
- `name` -> `repository_name`
- `full_name` -> `repository_full_name`
- `html_url` -> `repository_url`
- `default_branch` -> default branch metadata when available
- `private` -> visibility label derivation
### Branch
- `name` -> branch name shown in ticket detail
### Pull request
- `number` -> provider identifier shown in ticket detail
- `title` -> pull request title
- `state` -> pull request status
- `head.ref` -> source branch used for ticket-key matching
- `html_url` -> outbound link target
## Product and UX Implications
- GitHub connections should appear beside Gitea connections in user settings.
- The GitHub connection form should not require a base URL for GitHub Cloud.
- Project repository settings should allow mixing Gitea and GitHub repositories in the same project when the provider abstraction already supports this.
- Ticket branch and pull request sections should continue to be grouped by repository connection so provider context stays obvious.
## Explicitly Deferred
The provided GitHub API definition also contains app and installation endpoints, but those should not be part of release `0.3`.
Deferred items:
- GitHub App authentication with `GET /app`
- installation discovery with `GET /app/installations`
- installation token generation with `POST /app/installations/{installation_id}/access_tokens`
- installation-scoped repository listing with `GET /installation/repositories`
- GitHub Enterprise Server support
- webhooks
- review, merge, and status-check actions
- GraphQL usage
- branch creation from inside KanbanGit
## Release Outcome
If release `0.3` is completed as planned, KanbanGit should support GitHub repository awareness with the same core workflow currently targeted for Gitea:
- connect a provider account
- expose accessible repositories
- link repositories to projects
- surface ticket-related branches
- surface ticket-related pull requests
+33
View File
@@ -0,0 +1,33 @@
## Missing features
### Ticket
- general:
- new skill, user resources
- 02:
- Delete Projekt as Admin
- 03
- permission models? eg.g syncUserPermissions uses only db table
- mit morph auf perm user (z.b. team oder user)
- Project Permissions Service
- syncTeamMembers(Team $team, array $userIds): void → ist wrong here
- gate statt has permission methods
- permission for creating teams without beeing admind -> teamowner
- team roles
- 05
- ticket type remove build in
- → add is parentBool to ticketType -> remove system_key (maybe add slug)
- auto generate one parent one task on new project as now
- disable delete last child ticket type
- every form request removed unnecessary methods: like position in StoreProjectNamedSettingRequest
- use Arr:get(\$validated, 'value'). instead of these messages or \$request->value
- Made ticket priority more static(change to has one) in ticket, but only show if there are more than one configured.
- made story points more static(change to table field in table), but only show if checked in project settings → new value on Project: hasStoryPoints
- more ticket field types (string, string array, boolean)
- later:
- if deleting ticket type select a new ticket type which all existing ticket should get or select delete all tickets of that type
@@ -0,0 +1,32 @@
# 01 GitHub Provider Foundation and Auth Strategy
## Goal
Introduce GitHub as the second concrete Git provider behind the existing provider abstraction while keeping the first GitHub auth mode aligned with KanbanGit's current per-user connection model.
## Requirements
- Add GitHub as a supported provider key and provider client.
- Target GitHub Cloud on `https://api.github.com`.
- Keep project, ticket, and repository-connection core logic free from GitHub-specific assumptions wherever possible.
- The provider client must support the API surface needed for:
- authenticated user metadata
- repository listing
- repository lookup
- branch listing
- pull request listing
- The release must choose one initial GitHub auth strategy and document it clearly.
## Acceptance Criteria
- The codebase has a clear GitHub provider implementation behind the existing provider boundary.
- GitHub-specific HTTP details do not leak into ticket or project core logic.
- The selected GitHub auth strategy is compatible with the current `UserGitConnection` concept.
- The provider foundation is sufficient for later repository linking, branch discovery, and pull request visibility tickets in release `0.3`.
## Out of Scope
- GitHub App JWT handling
- GitHub installation tokens
- GitHub Enterprise Server support
- Webhook processing
@@ -0,0 +1,26 @@
# 02 User GitHub Connections and Repository Discovery
## Goal
Allow a user to connect GitHub in settings and expose the repositories that user can read through the chosen token.
## Requirements
- Add GitHub as an option in user Git connection settings.
- GitHub Cloud connections must use a fixed API base URL instead of asking the user for an instance URL.
- Connection verification must confirm repository read access.
- Authenticated user metadata from `GET /user` should be stored when available for display purposes.
- Accessible repositories must be loaded from the authenticated user's GitHub repository list.
## Acceptance Criteria
- A user can add, update, list, and remove a GitHub connection from settings.
- A token that can read repositories is accepted.
- A token that cannot read repositories is rejected with a clear validation error.
- Repositories available through the GitHub connection appear as selectable repository sources in project settings.
## Out of Scope
- OAuth browser login flows
- GitHub App installation authorization
- Background repository synchronization beyond on-demand fetches
@@ -0,0 +1,26 @@
# 03 Project GitHub Repository Connections
## Goal
Allow projects to link one or more GitHub repositories through the existing project repository settings workflow.
## Requirements
- Reuse the existing repository connection model and project settings flow for GitHub.
- A GitHub repository connection must store enough data to identify the provider and repository.
- Repository linking must remain protected by the appropriate project-level permissions.
- The repository list must make the provider source clear when a project uses more than one Git provider.
- The design should allow a project to hold both Gitea and GitHub repository connections when supported by the underlying provider abstraction.
## Acceptance Criteria
- An authorized user can add, edit, list, and remove GitHub repository connections for a project.
- A project can hold more than one GitHub repository connection.
- A project can display mixed-provider repository connections without ambiguity.
- The stored data remains compatible with the provider-neutral repository connection layer introduced in earlier releases.
## Out of Scope
- Cross-project shared repository connections
- Automatic background metadata refresh
- Organization-level permission management inside KanbanGit
@@ -0,0 +1,26 @@
# 04 GitHub Ticket Branch Discovery by Ticket Key
## Goal
Show GitHub branches related to a ticket by matching configured repository branches against the ticket key prefix.
## Requirements
- Add GitHub branch matches to the ticket detail view through the same provider-neutral branch section used for other providers.
- For each configured GitHub repository connection, identify branches whose names start with the ticket key.
- A matching branch must be shown on the ticket when its name starts with the exact ticket key, for example `AUTH-42-...`.
- Present matches in a way that makes the repository source and provider clear.
- The first implementation may use direct fetches or a simple cache, but it must not require a large background sync system.
## Acceptance Criteria
- A ticket with key `AUTH-42` shows GitHub branches such as `AUTH-42-login-form`.
- Branches that do not start with the ticket key are not shown.
- If multiple configured repositories contain matching branches, the ticket shows matches from each relevant repository.
- The branch section remains compatible with mixed-provider repository connections.
## Out of Scope
- Commit listing
- Branch creation from inside KanbanGit
- Cross-ticket branch disambiguation beyond exact ticket-key prefix matching
@@ -0,0 +1,29 @@
# 05 GitHub Ticket Pull Request Visibility
## Goal
Show GitHub pull requests related to a ticket alongside the matching branches in the ticket detail view.
## Requirements
- Add a GitHub pull requests section to the ticket detail view using the existing provider-neutral pull request presentation model.
- Pull requests must be associated to a ticket using the same ticket-key-based branch naming convention as branch discovery.
- Show enough pull request information to identify and open the matching item, at minimum:
- title
- provider identifier or number
- repository source
- status if available
- The implementation may derive pull request matches from source branch names.
## Acceptance Criteria
- A ticket shows GitHub pull requests whose source branch starts with the ticket key.
- Pull requests unrelated to the ticket key are not shown.
- The ticket detail view clearly separates branch matches from pull request matches.
- Pull request visibility remains compatible with mixed-provider repository connections.
## Out of Scope
- Pull request review actions inside KanbanGit
- Merge controls
- Status checks and CI reporting
@@ -0,0 +1,41 @@
# Release 0.3 - GitHub Integration
## Purpose
Add GitHub as the second supported Git provider with parity to the current Gitea-based repository, branch, and pull request visibility flows.
## API Basis
This release is planned from `docs/gitApiDocs/api.github.com.json`.
Primary endpoints for release `0.3`:
- `GET /user`
- `GET /user/repos`
- `GET /repos/{owner}/{repo}`
- `GET /repos/{owner}/{repo}/branches`
- `GET /repos/{owner}/{repo}/pulls`
## Release Decisions
- The first release targets GitHub Cloud on `https://api.github.com`.
- The first auth mode is a per-user token connection.
- Repository readability is the connection gate.
- Authenticated user profile data is an optional enrichment step for display metadata.
- GitHub App and installation flows are intentionally deferred.
## Tickets
- [01 GitHub Provider Foundation and Auth Strategy](01-github-provider-foundation-and-auth-strategy.md)
- [02 User GitHub Connections and Repository Discovery](02-user-github-connections-and-repository-discovery.md)
- [03 Project GitHub Repository Connections](03-project-github-repository-connections.md)
- [04 GitHub Ticket Branch Discovery by Ticket Key](04-github-ticket-branch-discovery-by-ticket-key.md)
- [05 GitHub Ticket Pull Request Visibility](05-github-ticket-pull-request-visibility.md)
## Deferred from This Release
- GitHub App authentication and installations
- GitHub Enterprise Server
- Webhooks
- Merge, review, and status-check actions
- Branch creation from ticket detail
+2
View File
@@ -6,9 +6,11 @@ This directory contains small, ordered implementation tickets grouped by release
- [Release 0.1 - Kanban, Ticketing, Users, and Permissions Foundation](0.1-kanban-foundation/01-admin-and-user-management-foundation.md) - [Release 0.1 - Kanban, Ticketing, Users, and Permissions Foundation](0.1-kanban-foundation/01-admin-and-user-management-foundation.md)
- [Release 0.2 - Gitea Integration](0.2-gitea-integration/01-git-provider-abstraction-and-gitea-foundation.md) - [Release 0.2 - Gitea Integration](0.2-gitea-integration/01-git-provider-abstraction-and-gitea-foundation.md)
- [Release 0.3 - GitHub Integration](0.3-github-integration/README.md)
## Scope notes ## Scope notes
- Release `0.1` covers the core Kanban, ticket, user, team, and permission foundation. - Release `0.1` covers the core Kanban, ticket, user, team, and permission foundation.
- Release `0.2` covers the first Git provider integration with Gitea. - Release `0.2` covers the first Git provider integration with Gitea.
- Release `0.3` covers GitHub Cloud as the second Git provider using the existing provider abstraction and user connection model.
- Roadmap and other currently out-of-scope items are intentionally not broken into tickets here. - Roadmap and other currently out-of-scope items are intentionally not broken into tickets here.
+1 -1
View File
@@ -22,10 +22,10 @@ import {
SidebarMenuButton, SidebarMenuButton,
SidebarMenuItem, SidebarMenuItem,
} from '@/components/ui/sidebar'; } from '@/components/ui/sidebar';
import { dashboard } from '@/routes';
import { index as adminTeams } from '@/routes/admin/teams'; import { index as adminTeams } from '@/routes/admin/teams';
import { index as adminUsers } from '@/routes/admin/users'; import { index as adminUsers } from '@/routes/admin/users';
import { index as projectsIndex } from '@/routes/projects'; import { index as projectsIndex } from '@/routes/projects';
import { dashboard } from '@/routes';
import type { NavItem } from '@/types'; import type { NavItem } from '@/types';
const page = usePage(); const page = usePage();
@@ -98,6 +98,7 @@ watch(
async (isOpen) => { async (isOpen) => {
if (!isOpen) { if (!isOpen) {
resetModalState(); resetModalState();
return; return;
} }
+1 -1
View File
@@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { Form, Head } from '@inertiajs/vue3'; import { Form, Head } from '@inertiajs/vue3';
import { Shield, Users } from 'lucide-vue-next'; import { Shield } from 'lucide-vue-next';
import TeamController from '@/actions/App/Http/Controllers/TeamController'; import TeamController from '@/actions/App/Http/Controllers/TeamController';
import Heading from '@/components/Heading.vue'; import Heading from '@/components/Heading.vue';
import InputError from '@/components/InputError.vue'; import InputError from '@/components/InputError.vue';
@@ -5,5 +5,4 @@ export type BoardColumnModel = {
project_id: number; project_id: number;
created_at: string; created_at: string;
updated_at: string; updated_at: string;
[key: string]: unknown;
}; };
@@ -4,5 +4,4 @@ export type ProjectModel = {
key: string; key: string;
created_at: string; created_at: string;
updated_at: string; updated_at: string;
[key: string]: unknown;
}; };
-1
View File
@@ -7,5 +7,4 @@ export type TeamModel = {
users: UserModel[]; users: UserModel[];
created_at: string; created_at: string;
updated_at: string; updated_at: string;
[key: string]: unknown;
}; };