Skip to content

Commit 5d66f64

Browse files
authored
Merge pull request #748 from alan-turing-institute/staging
Release: Docker and Prisma 7 deployment fixes
2 parents 5bd2e2a + da087bd commit 5d66f64

File tree

5 files changed

+46
-12
lines changed

5 files changed

+46
-12
lines changed

.beads/issues.jsonl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
{"id":"AssurancePlatform-59h","title":"My first issue","status":"closed","priority":2,"issue_type":"task","created_at":"2025-12-24T10:21:42.184897Z","updated_at":"2025-12-24T10:23:10.736974Z","closed_at":"2025-12-24T10:23:10.736974Z","close_reason":"Just testing"}
1010
{"id":"AssurancePlatform-5fm","title":"Phase 2d: Auth Cleanup (RefreshToken Removal)","description":"Final cleanup of the legacy RefreshToken authentication system. BLOCKED until 2025-01-19 (30 days after JWT-only deployment).\n\nPre-requisite: JWT-only auth (USE_JWT_ONLY_AUTH=true) must be stable in production for 30+ days.\n\nCode Cleanup:\n- [ ] Delete lib/auth/refresh-token-service.ts\n- [ ] Delete lib/auth/validate-session.ts\n- [ ] Delete lib/auth/feature-flags.ts\n- [ ] Update lib/auth-options.ts - Remove legacy RefreshToken code\n- [ ] Update middleware.ts - Remove stale session detection\n- [ ] Update types/next-auth.d.ts - Remove key from Session type\n- [ ] Remove USE_JWT_ONLY_AUTH from environment variables\n\nClient Component Cleanup (remove session?.key references):\n- [ ] components/common/node-edit.tsx\n- [ ] components/common/new-link-form.tsx\n- [ ] components/common/edit-form.tsx\n- [ ] components/common/create-form.tsx\n- [ ] components/cases/orphan-elements.tsx\n\nTest Updates:\n- [ ] app/(landing)/_components/__tests__/header.test.tsx\n- [ ] lib/__tests__/auth-helpers.test.ts\n\nDatabase Migration:\n- [ ] Create Prisma migration to drop RefreshToken table\n- [ ] Run on staging first\n- [ ] Run on production","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-07T12:58:17.791742Z","created_by":"cburr","updated_at":"2026-01-11T09:58:10.515745Z","closed_at":"2026-01-11T09:58:10.515745Z","close_reason":"Merged to staging. Removed RefreshToken model, feature flags, and legacy session token references. Migration created to drop refresh_tokens table.","labels":["auth","tech-debt"],"dependencies":[{"issue_id":"AssurancePlatform-5fm","depends_on_id":"AssurancePlatform-dpk","type":"parent-child","created_at":"2026-01-09T09:38:44.305533Z","created_by":"cburr"}],"comments":[{"id":3,"issue_id":"AssurancePlatform-5fm","author":"cburr","text":"Unblocked: JWT-only auth has been stable in production for 30+ days. Ready to proceed with RefreshToken removal.","created_at":"2026-01-09T17:30:59Z"}]}
1111
{"id":"AssurancePlatform-5hb","title":"Implement user data retention policy (2-3 years inactivity)","description":"Implement a data retention policy to comply with UK GDPR storage limitation principle.\n\n## Requirements\n- Delete user accounts after 2-3 years of inactivity (based on `lastLoginAt`)\n- Send email warnings before deletion:\n - First warning: 30 days before deletion\n - Final warning: 7 days before deletion\n- Offer data export option before deletion\n\n## Technical considerations\n- Scheduled background job to check for inactive users\n- Soft-delete with 30-day grace period before hard deletion\n- Handle edge cases:\n - Users who never created any cases (shorter retention?)\n - Inactive users who own cases shared with active team members\n- Document retention policy for users (privacy policy update)\n\n## Reference\n- ICO guidance on storage limitation\n- `lastLoginAt` field already exists on User model (prisma/schema.prisma:70)","status":"closed","priority":2,"issue_type":"feature","created_at":"2026-01-16T17:18:10.491183Z","created_by":"cburr","updated_at":"2026-01-18T08:03:04.115715Z","closed_at":"2026-01-18T08:03:04.115715Z","close_reason":"Data retention policy documented in content/data-retention-policy.mdx"}
12+
{"id":"AssurancePlatform-5l1","title":"Staging Azure App Service not starting after deployment","description":"## Problem\n\nThe staging Azure App Service (staging-assuranceplatform) returns 503 errors after deployment. The container fails to start despite successful Docker image push to ghcr.io.\n\n## Symptoms\n\n- Health endpoint returns 503: `https://staging-assuranceplatform.azurewebsites.net/api/health`\n- Container was using stale image tag (`staging-acc8a9a`) instead of `staging`\n- Manual update to `staging` tag and restart did not resolve\n\n## Investigation Done\n\n1. **Verified image pushed successfully** - GitHub Actions Build workflow completed\n2. **Checked container config** - Was pinned to old tag, updated to `staging`\n3. **Restart attempts** - `az webapp restart`, stop/start cycle - all returned 503\n4. **Logs checked** - Kudu logs show deployment requests but no container startup logs visible via CLI\n\n## Commands Tried\n\n```bash\naz webapp restart --name staging-assuranceplatform --resource-group AssuranceSiteStaging\naz webapp stop/start --name staging-assuranceplatform --resource-group AssuranceSiteStaging\naz webapp config container set --container-image-name \"ghcr.io/alan-turing-institute/assuranceplatform/tea-app:staging\"\n```\n\n## Next Steps\n\n1. Check Azure Portal → App Services → staging-assuranceplatform → Diagnose and solve problems → Container Crash\n2. Check Deployment Center → Logs for container startup errors\n3. Verify DATABASE_URL and other env vars are correct for staging\n4. Check if container is pulling correct image (may need to clear container cache)\n5. Consider checking if the new seed workflow or other changes affected startup\n\n## Related\n\n- Build workflow: https://github.com/alan-turing-institute/AssurancePlatform/actions/runs/21109956120\n- Release v0.3.0 deployed successfully to main\n- Issue appeared after merging dev seed database feature\n\n## Impact\n\n- Staging environment unavailable for testing\n- Changelog page cannot be verified at `/docs/technical-guide/ci-cd-pipeline/changelog`","status":"closed","priority":1,"issue_type":"bug","created_at":"2026-01-18T10:50:52.72571Z","created_by":"cburr","updated_at":"2026-01-18T15:04:12.638061Z","closed_at":"2026-01-18T15:04:12.638061Z","close_reason":"Fixed: Prisma now copied from builder stage with correct ownership for nextjs user","comments":[{"id":13,"issue_id":"AssurancePlatform-5l1","author":"cburr","text":"Additional fixes required after initial resolution:\n\n## Root Causes Found\n\n1. Docker build OOM - Next.js build exceeded default Node.js heap. Fixed by adding NODE_OPTIONS to Dockerfile.\n\n2. Prisma migration table missing - The _prisma_migrations table did not exist in staging DB.\n\n3. Database permissions - tea_app user lacked CREATE permission on public schema.\n\n## Fixes Applied\n\nCommits: 6a429b5 (NODE_OPTIONS), e1b4893 (seed workflow permissions)\n\nSTAGING_DATABASE_URL secret updated to use admin credentials.\n\nSeed workflow now grants permissions after reset.","created_at":"2026-01-18T20:48:35Z"}]}
1213
{"id":"AssurancePlatform-5o1","title":"Code Quality: Replace raw SQL pattern in health check","description":"The health check in app/api/health/route.ts (line 34) uses $queryRaw with a hardcoded query.\n\n**Current code:**\n```typescript\nawait prisma.$queryRaw`SELECT 1`;\n```\n\n**Issue:** While this specific usage is safe (hardcoded query with no user input), using $queryRaw sets a pattern that could be dangerous if copied elsewhere.\n\n**Fix:** Replace with a safer alternative:\n```typescript\nawait prisma.user.count({ take: 1 }); // Prisma ORM method\n```\n\n**Confidence:** 80%","status":"closed","priority":2,"issue_type":"chore","created_at":"2025-12-24T10:27:30.403578Z","updated_at":"2026-01-02T10:57:51.766249Z","closed_at":"2026-01-02T10:57:51.766249Z","close_reason":"Replaced $queryRaw with prisma.user.count({ take: 1 }) and added unit tests","labels":["code-quality"]}
1314
{"id":"AssurancePlatform-5oy","title":"Auto-seed dev database from backup on container creation","description":"Create a simple, lightweight dev/test database instead of using the full prod backup.\n\n## Purpose\n- Fast local development setup\n- Testing infrastructure for Phase 5 (g2a)\n- Reproducible test data for CI/CD and Playwright E2E tests\n\n## Requirements\n\n### Users\nCreate a small set of test users with known credentials:\n- **chris** - primary dev account (cburr)\n- **alice** - test user, team member (internal collaborator)\n- **bob** - test user, team member (internal collaborator)\n- **charlie** - test user, no team membership (external collaborator)\n\n### Team Structure\n- **Test Team** - alice and bob are members (alice as admin, bob as member)\n- charlie deliberately excluded to test internal vs external collaboration flows\n\n### Assurance Cases\nEach user should have cases of varying complexity:\n- **Simple**: Single goal with 1-2 claims and evidence (for quick tests)\n- **Medium**: Nested structure with strategies, multiple claims, evidence links\n- Cases in different states: draft, published, shared\n- At least one case shared between team members\n- At least one case shared with charlie (external sharing)\n\n### Data to Support E2E User Journeys\n1. **Authentication** - users with known passwords for login tests\n2. **Case Management** - cases to edit/delete, space to create new\n3. **Collaboration** - shared cases, existing comments to verify\n4. **Team Management** - existing team with members and permissions\n5. **Community Case Studies** - at least one published case study\n6. **User Settings** - users that can update profile/password\n7. **Import/Export** - cases suitable for export testing\n\n### Credentials Storage\n- Store passwords in a file that is NOT committed to git\n- Add to .gitignore\n- Document location for developers\n\n### Implementation\n1. Create seed SQL file: `prisma/seed/dev-seed.sql`\n2. Mount to `/docker-entrypoint-initdb.d/` in docker-compose.development.yml\n3. Runs automatically on fresh container (empty data directory)\n\n## Notes\n- Replaces current workflow of restoring from `backups/prod-backup-*.sql`\n- Seed data should be minimal but realistic\n- Passwords file location: `prisma/seed/.credentials` (gitignored)\n- Reference: Phase 5 (g2a) Critical User Journeys","status":"in_progress","priority":2,"issue_type":"feature","created_at":"2026-01-14T07:34:21.445679Z","created_by":"cburr","updated_at":"2026-01-18T08:23:30.059116Z"}
1415
{"id":"AssurancePlatform-5s1","title":"Create database seeding utilities","description":"Create utilities for seeding test database with realistic data.\n\n## Location\nsrc/__tests__/utils/seed-utils.ts\n\n## API Design\n```typescript\n// Seed a complete test user with case\nexport async function seedTestUser(tx: PrismaTransaction): Promise\u003cTestUser\u003e\n\n// Seed a complete assurance case with elements\nexport async function seedTestCase(tx: PrismaTransaction, ownerId: string): Promise\u003cTestCase\u003e\n\n// Seed a team with members\nexport async function seedTestTeam(tx: PrismaTransaction): Promise\u003cTestTeam\u003e\n```\n\n## Data Sources\n- Adapt from existing mock-data.ts\n- Use test-factories.ts patterns\n- Ensure realistic relationships","status":"open","priority":1,"issue_type":"task","created_at":"2026-01-15T12:33:00.811758Z","created_by":"cburr","updated_at":"2026-01-15T12:33:00.811758Z","dependencies":[{"issue_id":"AssurancePlatform-5s1","depends_on_id":"AssurancePlatform-x8n","type":"blocks","created_at":"2026-01-15T12:33:07.54206Z","created_by":"cburr"}]}

.github/workflows/seed-staging.yml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ on:
77
push:
88
branches:
99
- staging
10+
paths-ignore:
11+
- ".beads/**"
12+
- "*.md"
13+
- "docs/**"
1014

1115
jobs:
1216
seed:
@@ -37,7 +41,20 @@ jobs:
3741
DATABASE_URL: ${{ secrets.STAGING_DATABASE_URL }}
3842
run: npx prisma migrate reset --force
3943

44+
- name: Grant permissions to app user
45+
env:
46+
DATABASE_URL: ${{ secrets.STAGING_DATABASE_URL }}
47+
run: |
48+
psql "$DATABASE_URL" -c "
49+
GRANT USAGE, CREATE ON SCHEMA public TO tea_app;
50+
GRANT ALL ON ALL TABLES IN SCHEMA public TO tea_app;
51+
GRANT ALL ON ALL SEQUENCES IN SCHEMA public TO tea_app;
52+
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES TO tea_app;
53+
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON SEQUENCES TO tea_app;
54+
"
55+
4056
- name: Run seed script
4157
env:
4258
DATABASE_URL: ${{ secrets.STAGING_DATABASE_URL }}
59+
SEED_USER_PASSWORD: ${{ secrets.SEED_USER_PASSWORD }}
4360
run: npx tsx prisma/seed/dev-seed.ts

Dockerfile

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ ENV DATABASE_URL=${DATABASE_URL}
6363
# Dummy DATABASE_URL is needed at build time for Prisma config and Next.js static analysis
6464
# The actual URL is provided at runtime via Azure environment variables
6565
ENV DATABASE_URL="postgresql://dummy:dummy@localhost:5432/dummy"
66+
# Increase Node.js memory limit for Next.js build (Nextra compilation requires more memory)
67+
ENV NODE_OPTIONS="--max-old-space-size=4096"
6668
RUN npx prisma generate && corepack enable pnpm && pnpm build
6769

6870
# 3. Production image, copy all the files and run next
@@ -73,9 +75,6 @@ RUN \
7375
addgroup -g 1001 -S nodejs; \
7476
adduser -S nextjs -u 1001
7577

76-
# Install Prisma CLI for runtime migrations
77-
RUN npm install -g prisma@7.0.0 && npm install prisma@7.0.0
78-
7978
COPY --from=builder --link /app/public ./public
8079

8180
# Automatically leverage output traces to reduce image size
@@ -88,6 +87,12 @@ COPY --from=builder --link --chown=1001:1001 /app/prisma/schema.prisma ./prisma/
8887
COPY --from=builder --link --chown=1001:1001 /app/prisma/migrations ./prisma/migrations
8988
COPY --from=builder --link --chown=1001:1001 /app/prisma.config.ts ./prisma.config.ts
9089

90+
# Install Prisma CLI for runtime migrations
91+
# Install to /opt/prisma to avoid conflicts with Next.js standalone node_modules
92+
# Also install dotenv required by prisma.config.ts
93+
RUN mkdir -p /opt/prisma && cd /opt/prisma && npm init -y && npm install prisma@7.0.0 dotenv && \
94+
chown -R nextjs:nodejs /opt/prisma
95+
9196
# Copy and set up entrypoint script
9297
COPY --link --chown=1001:1001 scripts/docker-entrypoint.sh ./docker-entrypoint.sh
9398
RUN chmod +x ./docker-entrypoint.sh

prisma/seed/dev-seed.ts

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ type Credentials = {
4242

4343
function loadCredentials(): Credentials {
4444
const credentialsPath = join(__dirname, ".credentials");
45+
46+
// First, try to load from .credentials file (local development)
4547
try {
4648
const content = readFileSync(credentialsPath, "utf-8");
4749
const credentials: Credentials = {};
@@ -51,19 +53,28 @@ function loadCredentials(): Credentials {
5153
credentials[username] = password;
5254
}
5355
}
56+
console.log("Loaded credentials from .credentials file");
5457
return credentials;
5558
} catch {
56-
console.error(
57-
"Failed to load .credentials file. Using fallback passwords."
58-
);
59-
// Fallback passwords that meet validation rules
59+
// File doesn't exist - check for environment variable (CI/staging)
60+
}
61+
62+
// Fall back to SEED_USER_PASSWORD environment variable (CI/staging)
63+
const envPassword = process.env.SEED_USER_PASSWORD;
64+
if (envPassword) {
65+
console.log("Using SEED_USER_PASSWORD from environment");
6066
return {
61-
chris: "DevPassword#1",
62-
alice: "DevPassword#2",
63-
bob: "DevPassword#3",
64-
charlie: "DevPassword#4",
67+
chris: envPassword,
68+
alice: envPassword,
69+
bob: envPassword,
70+
charlie: envPassword,
6571
};
6672
}
73+
74+
throw new Error(
75+
"No credentials available. Either create prisma/seed/.credentials file " +
76+
"or set SEED_USER_PASSWORD environment variable."
77+
);
6778
}
6879

6980
async function main() {

scripts/docker-entrypoint.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
set -e
33

44
echo "Running database migrations..."
5-
npx prisma migrate deploy
5+
NODE_PATH=/opt/prisma/node_modules /opt/prisma/node_modules/.bin/prisma migrate deploy
66
echo "Migrations applied successfully."
77

88
echo "Starting Next.js server..."

0 commit comments

Comments
 (0)