Initial commit: TravelHub multi-tenant flight booking platform

Angular + Go + PostgreSQL sample with strict per-tenant isolation.

- Backend: Go API (basic auth, tenant-scoped repository layer, pgx pool)
- Frontend: Angular 22 SPA (search, checkout, bookings, dashboard)
- Database: schema, seed data and demo bookings migrations
- Tests: 311 across Go (integration), Angular (unit) and Playwright (e2e),
  plus a generated evidence report with PDF export
- Security: whitebox VAPT report under security/

Secrets (.env, tokens, DB credentials) are git-ignored.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
nilesh.p
2026-09-13 11:38:01 +05:30
co-authored by Claude Opus 4.8
commit 4d3eb18a6c
129 changed files with 25424 additions and 0 deletions
+66
View File
@@ -0,0 +1,66 @@
/**
* The console is built to work at phone width. These checks guard the layout
* rules that make that true -- chiefly that nothing forces a horizontal scroll.
*/
import { expect, test } from '../fixtures/test';
import { SKYLINE_AGENT } from '../fixtures/accounts';
/** True when the document is wider than the viewport. */
async function scrollsSideways(page: import('@playwright/test').Page): Promise<boolean> {
return page.evaluate(() => document.documentElement.scrollWidth > window.innerWidth + 1);
}
test.describe('Layout', () => {
test('the sign-in screen fits without sideways scrolling', async ({ page, login }) => {
await page.setViewportSize({ width: 390, height: 844 });
await login.goto();
expect(await scrollsSideways(page)).toBe(false);
// The decorative panel is hidden rather than squeezed.
await expect(page.locator('.hero')).toBeHidden();
await expect(login.submit).toBeVisible();
});
test('the console screens fit at phone width', async ({ page, signInAs, shell, search }) => {
await page.setViewportSize({ width: 390, height: 844 });
await signInAs(SKYLINE_AGENT);
expect(await scrollsSideways(page)).toBe(false);
await shell.goToSearch();
await search.settled();
expect(await scrollsSideways(page)).toBe(false);
await expect(search.results.first()).toBeVisible();
await shell.goToBookings();
expect(await scrollsSideways(page)).toBe(false);
});
test('wide tables scroll inside their own container', async ({ page, signInAs, shell }) => {
await page.setViewportSize({ width: 390, height: 844 });
await signInAs(SKYLINE_AGENT);
await shell.goToBookings();
const wrapper = page.locator('.table-wrap').first();
await expect(wrapper).toBeVisible();
// The table may overflow; the page must not.
expect(await scrollsSideways(page)).toBe(false);
});
test('the sidebar collapses into a top bar on narrow screens', async ({ page, signInAs }) => {
await page.setViewportSize({ width: 390, height: 844 });
await signInAs(SKYLINE_AGENT);
const sidebar = page.locator('.sidebar');
const content = page.locator('.content');
const sidebarBox = await sidebar.boundingBox();
const contentBox = await content.boundingBox();
expect(sidebarBox).not.toBeNull();
expect(contentBox).not.toBeNull();
// Stacked, not side by side.
expect(contentBox!.y).toBeGreaterThan(sidebarBox!.y);
});
});