Contributing
Thank you for contributing to KoAkademy! Contributions should be focused, well-tested, and safe for institutions that self-host the platform.
Before Opening Work
Section titled “Before Opening Work”- Search existing issues and pull requests to avoid duplicate effort.
- Open a discussion or feature issue first for substantial behavior or architectural changes so maintainers can confirm direction.
- Do not post vulnerabilities in public issues. Follow SECURITY.md to report security concerns privately through GitHub Advisory.
- Keep pull requests focused: avoid mixing feature work with mass formatting, dependency bumps, or generated file changes.
- Note: KoAkademy is an open-source project maintained by volunteers; no fixed response-time or merge-time SLA is promised.
Development Setup
Section titled “Development Setup”KoAkademy runs on PHP 8.5, Laravel 13, Inertia 3, React 19, and Node.js 22. Follow Development for full installation instructions:
# 1. Clone the repository and install dependenciesgit clone https://github.com/yukazakiri/koakademy.gitcd koakademycomposer installnpm ci
# 2. Configure environment and databasecp .env.example .envphp artisan key:generatetouch database/database.sqlitephp artisan migrate
# 3. Build frontend assets and start serversnpm run buildphp artisan serveRun npm run dev in a separate terminal when working on React portal components with hot module replacement (HMR).
First Contribution Walkthrough
Section titled “First Contribution Walkthrough”Whether you are fixing a bug or adding a feature, follow this step-by-step workflow:
- Create a topic branch from
master:Terminal window git checkout -b fix/enrollment-fee-calculation - Write or update a Pest test that reproduces the issue or verifies the new behavior.
- Implement your changes following repository conventions (strict types in PHP, TypeScript in React).
- Run local validation before opening your PR.
Contributor Code Samples
Section titled “Contributor Code Samples”1. Backend Feature Test (Pest 5)
Section titled “1. Backend Feature Test (Pest 5)”Write feature tests under tests/Feature/. Use model factories and actingAs() to verify authorization and response payloads:
<?php
declare(strict_types=1);
use App\Enums\UserRole;use App\Models\StudentEnrollment;use App\Models\User;use Inertia\Testing\AssertableInertia;
use function Pest\Laravel\actingAs;
it('allows registrars to view pending enrollment applicants', function (): void { $registrar = User::factory()->create(['role' => UserRole::Registrar]); $enrollment = StudentEnrollment::factory()->create();
actingAs($registrar) ->get(portalUrlForAdministrators('/administrators/enrollments')) ->assertOk() ->assertInertia(fn (AssertableInertia $page): AssertableInertia => $page ->component('administrators/enrollment/index', false) ->has('enrollments.data', 1) ->where('enrollments.data.0.id', $enrollment->id) );});
it('forbids unauthorized roles from updating enrollment records', function (): void { $student = User::factory()->create(['role' => UserRole::Student]); $enrollment = StudentEnrollment::factory()->create();
actingAs($student) ->put(portalUrlForAdministrators("/administrators/enrollments/{$enrollment->id}"), [ 'status' => 'approved', ]) ->assertForbidden();});2. Frontend React Form (Inertia 3 + Wayfinder)
Section titled “2. Frontend React Form (Inertia 3 + Wayfinder)”Frontend components live in resources/js/pages/. Use generated Wayfinder route helpers from @/actions or @/routes with Inertia’s useForm:
import { store } from "@/actions/App/Http/Controllers/AdministratorEnrollmentPolicyController";import { Button } from "@/components/ui/button";import { Input } from "@/components/ui/input";import { Label } from "@/components/ui/label";import { useForm } from "@inertiajs/react";import type { FormEvent } from "react";
interface CreatePolicyProps { onSuccess?: () => void;}
export function CreatePolicyForm({ onSuccess }: CreatePolicyProps) { const form = useForm({ name: "", preset: "legacy", school_id: null as number | null, });
const handleSubmit = (event: FormEvent<HTMLFormElement>) => { event.preventDefault();
form.post(store.url(), { preserveScroll: true, onSuccess: () => { form.reset(); onSuccess?.(); }, }); };
return ( <form onSubmit={handleSubmit} className="space-y-4"> <div className="space-y-2"> <Label htmlFor="name">Blueprint Name</Label> <Input id="name" value={form.data.name} onChange={(e) => form.setData("name", e.target.value)} placeholder="College enrollment foundation" aria-invalid={Boolean(form.errors.name)} /> {form.errors.name && ( <p className="text-destructive text-sm" role="alert"> {form.errors.name} </p> )} </div>
<Button type="submit" disabled={form.processing}> {form.processing ? "Saving..." : "Create Blueprint"} </Button> </form> );}Pull Request Checklist
Section titled “Pull Request Checklist”Before submitting your pull request, verify that every check passes locally:
# 1. Format and check PHP code stylevendor/bin/pint --test
# 2. Run backend test suitephp artisan test --parallel --compact
# 3. Build frontend bundlenpm run build
# 4. Check documentation mirrors and link integritynpm run docs:check
# 5. Build documentation sitenpm --prefix docs run build
# 6. Verify production Docker Compose syntaxKOAKADEMY_ENV_FILE=.env.production.example \ docker compose --env-file .env.production.example -f compose.production.yaml config --quietReview Standards
Section titled “Review Standards”- Tests: Add or update Pest tests for all behavioral changes.
- Migrations: Add new migrations for schema changes; never modify or delete historical, released migrations.
- Documentation: When user-visible behavior, configuration, or architecture changes, update the canonical root docs and run
npm run docs:sync. - Secrets & Data: Ensure no credentials, personal records, tokens, or environment files are included in commits.
- PR Titles: Use a concise, descriptive title. CI validates Conventional Commit format (e.g.,
feat(enrollment): add scholarship fee overrideorfix(auth): preserve tenant scope on 2FA challenge).
Code Style & Conventions
Section titled “Code Style & Conventions”- PHP: Strict typing enabled (
declare(strict_types=1);on all new files), formatted with Laravel Pint. Follow Laravel 13 patterns (Form Requests, Eloquent Policies, Enums). - TypeScript / React: Strict TypeScript, React 19 patterns, shadcn/ui components, and Tailwind CSS 4 utility classes.
- Accessibility: Ensure keyboard accessibility, visible focus rings, ARIA labels for icon buttons, and respect for
prefers-reduced-motion.
Documentation Ownership
Section titled “Documentation Ownership”KoAkademy maintains a single-source documentation system:
| Location | Role | How to Edit |
|---|---|---|
GETTING_STARTED.md, DEPLOYMENT.md, CONFIGURATION.md, TROUBLESHOOTING.md, DEVELOPMENT.md, ARCHITECTURE.md, CONTRIBUTING.md, FAQ.md | Canonical Sources | Edit directly in the root directory. |
docs/src/content/docs/start-here/contributing.mdx, etc. | Generated Mirrors | Do not edit manually. Run npm run docs:sync. |
docs/src/content/docs/system/*, docs/src/content/docs/user-guide/*, docs/src/content/docs/enrollment-policies/*, docs/src/content/docs/api/* | Native Docs Pages | Edit directly under docs/src/content/docs/. |
Standalone Module Contributions
Section titled “Standalone Module Contributions”Standalone domain extensions (such as the Forms module) live in dedicated repositories under the KoAkademy module registry. Check the Module Creation Guide and registry guidelines before publishing a new module package.
Regulatory Report Providers
Section titled “Regulatory Report Providers”Regulatory exports use a configuration-driven adapter contract so contributors can add compatible providers without coupling the shared registrar controller to one jurisdiction. Read the Regulatory Report Provider guide before changing this area.
Only the CHED E-Form B/C provider is built into this repository today. A new provider is an opt-in addition: it must implement App\Contracts\RegulatoryReportAdapter, add a definition under config/regulatory-reports.php (or an equivalent module configuration), and include authorization, tenant-isolation, preview, and workbook tests. Do not describe an unimplemented provider as supported, and do not add provider-specific assumptions to shared school or enrollment models.
If a provider has a user-facing registrar template, add its frontend template definition and renderer as part of the same contribution. The generic preview and export routes are available to configured providers, while the existing CHED template and legacy CHED routes remain compatible with current installations.
License & Legal
Section titled “License & Legal”By contributing, you agree that your code will be licensed under KoAkademy’s GNU AGPL-3.0-or-later license. Ensure you have the rights to submit the code and preserve copyright notices for third-party material.