Deliverable 08 · Develop
Drupal Build & QA
The stack, architecture, custom module, workflow and roles, accessibility checklist, QA results and launch readiness.
The stack
Palmetto Ridge runs on Drupal, the content management system used by hundreds of colleges and universities. We kept the stack deliberately conventional: core Drupal features first, a small number of well-supported contributed modules, and one custom module and theme for everything specific to the college.
Platform
Drupal 11.4.8 on PHP 8.5
SQLite locally for a zero-setup demo; MySQL or MariaDB in production. Drush 13 for the command line, Composer for dependencies.
Core & contributed
Proven building blocks
Core Views, Content Moderation, Workflows and Media Library. Contributed: Gin admin theme, Admin Toolbar, Pathauto and Token.
Custom
prjc_core + palmetto
One module for the dashboard, portal, Request Info form and access rules. One theme (base: Stable 9) for the public site and brand.
Architecture
Read from top to bottom: who uses the site, what they see, the Drupal features underneath, the college-specific code, and where everything is stored. The last layer is planned, not built.
People
Experience
Drupal 11 core
Custom code
Data
Future integrations
Content model
| Content type | Used for | Key fields |
|---|---|---|
| Article | News stories | Image, tags |
| Basic page | About, admissions and policy pages | Body, menu placement |
| Event | Open houses, games, deadlines, performances | Date & time range, category, location |
| Program | The 33 degrees and certificates in the finder | Area of study, credential, credit hours, length, format, careers |
| Team | The 11 Hawks athletic teams | Season, head coach, record, home venue |
| Person | The faculty and staff directory | Title, department, photo, contact details, leadership flag |
| Portal Announcement | Messages shown only inside the Hawk Portal | Audience, priority |
| Inquiry | Request Info submissions. Never published. | Student type, program of interest, status |
Custom module
The prjc_core module holds everything Drupal does not do out of the box for a college. Each route is protected by a named permission, not by hiding a link.
| Route | Purpose | Who can open it |
|---|---|---|
/admin/dashboard | Staff Dashboard: greeting, stats, action tiles, review queue, events and inquiries. Staff land here after signing in. | Staff “Use the staff dashboard” permission |
/portal | Hawk Portal for students. Anonymous visitors see a branded sign-in screen; signed-in students see their dashboard. | Everyone sign-in screen · Students dashboard |
/future-students/request-info | Request Info form. Saves each submission as an unpublished Inquiry with status New for Admissions. | Everyone |
/admin/dashboard/campus-alert | Campus alert banner: one switch shows a red (urgent) or brass (notice) banner at the top of every public page and the Hawk Portal. | Communications |
/site-dev | This design-process case study and the approved prototype. | Staff “Use the staff dashboard” permission |
Access hooks
hook_node_access() keeps Portal Announcements visible only to students and staff, and Inquiries only to the Admissions role, even if someone guesses the URL.
Login redirect
hook_user_login() sends staff to the dashboard and students to the portal, so nobody lands on a confusing Drupal user page.
Friendly names
A field_full_name on user accounts shows “Maya Thompson” on the dashboard and as content author, instead of a username.
Editorial workflow & roles
Every content type except Inquiry uses the same workflow, built with core Content Moderation: Draft, then Needs review, then Published (with Archived for retired content). Every save keeps a revision, so any change can be rolled back.
State 1
Draft
Work in progress. Visible only to staff.
State 2
Needs review
Sent for review. Appears in “Needs your attention” on the dashboard.
State 3
Published
Live on the website. Editing creates a new draft without touching the live version.
State 4
Archived
Removed from the site but kept, with full history.
| Permission | Content Editor | Communications | Admissions | Athletics | Student |
|---|---|---|---|---|---|
| Use the staff dashboard | ✓ | ✓ | ✓ | ✓ | — |
| Write news, pages, events, announcements | ✓ | ✓ | Pages, events, announcements | News, events | — |
| Edit programs | — | ✓ | ✓ | — | — |
| Edit teams | — | ✓ | — | ✓ | — |
| Send for review | ✓ | ✓ | ✓ | ✓ | — |
| Publish & archive | — | ✓ | — | — | — |
| Menus, homepage blocks, full HTML | — | ✓ | — | — | — |
| Turn the campus alert banner on/off | — | ✓ | — | — | — |
| Manage enrollment inquiries | — | — | ✓ | — | — |
| Use the Hawk Portal | ✓ | ✓ | ✓ | ✓ | ✓ |
Only Communications can publish. Everyone else sends work for review, so a second pair of eyes sees every page before it goes live.
Build approach
The whole site can be rebuilt from an empty folder with a handful of commands. Nothing important lives only in the database or in someone’s memory.
Scripts rebuild everything
scripts/build.phpcreates vocabularies, content types, fields, the review workflow, roles and permissions, and URL patterns.scripts/views.phpcreates every listing: program finder, news, events, directory, teams and the inquiries admin.scripts/content.phploads the demo content: 33 programs, 24 people, 11 teams, news and events.- Each script is safe to run again; it skips anything that already exists.
Config, git and no Docker
- Site configuration is exported as YAML to
config/sync, so every setting is reviewable in git. - The code lives in a private GitHub repository; the database, uploaded files and local credentials are git-ignored.
- No Docker or database server needed locally: PHP’s built-in web server plus SQLite runs the full site.
- Staff sign in locally with a one-time link from
drush uli.
Accessibility checklist
Checked against WCAG 2.2 Level AA on the public site, the Hawk Portal and the Staff Dashboard.
- Text contrast of at least 4.5:1 (most pairings reach AAA)
- Visible 3px brass focus ring on every link, button and field
- “Skip to main content” link as the first focusable element
- One H1 per page and a logical heading order
- All functionality available by keyboard, including the menus
- Tap targets at least 44 × 44px on mobile
- Every form field has a visible label and clear error messages
- Alt text required on every uploaded image
- Content reflows at 320px with no horizontal scrolling
- Page language set, and descriptive page titles on every route
QA test plan & results
Testing covered what visitors see, what staff can do, and what nobody should be able to reach. Four issues were caught and fixed before sign-off.
| Test | Method | Result |
|---|---|---|
| Every public page loads | Requested every public URL and checked the HTTP status | Pass all 200 |
| Missing pages handled | Requested a made-up URL | Pass 404 |
| No PHP errors | Reviewed the Drupal log after a full crawl | Pass zero errors |
| Staff routes are locked | Opened staff-only routes as an anonymous visitor | Pass 403 Access denied |
| Review workflow on the edit form | Opened the editor form as a Content Editor | Pass Draft / Needs review / Published |
| Request Info saves privately | Submitted the form, checked the result, then removed the test record | Pass unpublished Inquiry, status New |
| Campus alert banner | Turned it on from the Dashboard as Communications, checked three public pages as a visitor, then turned it off | Pass |
| Program pre-selected on Request Info | Followed “Request info” from the Accounting page and checked the form’s program field | Pass |
| Mobile menu | Opened, navigated and closed the menu at 375px | Pass |
| Responsive layouts | Homepage and Hawk Portal checked at 375px and 1280px | Pass |
| Database not downloadable | Requested the SQLite file’s URL. It had been placed inside the web root; moved outside and re-tested | Fixed now 404 |
| Portal sign-in screen styled | Viewed /portal signed out. It rendered unstyled; added the theme template and a “Back to the website” link | Fixed |
| Listing grids render | Stable 9 does not output the Views wrapper classes the theme’s grids rely on; added a Views template to restore them | Fixed |
| Program descriptions visible | The body field was hidden on the new content types; enabled it on every form and display | Fixed |
12
Checks run
8
Passed first time
4
Caught and fixed before sign-off
Performance
Many students browse on phones and prepaid data plans, so the site is built to be light without giving up photography.
~200 KB
Average scene photo, JPEG quality 60; headshots ~75 KB
1
Stylesheet per page with CSS aggregation
0
Icon fonts or front-end frameworks
Cached
Whole pages for anonymous visitors
- CSS and JS aggregation combines and minifies files so each page makes very few requests.
- Image compression: photos are resized for the web and saved at JPEG quality 60, averaging about 200 KB per scene photo and about 75 KB per headshot across 109 photos; lazy loading means a page only downloads the photos a visitor scrolls to.
- Lazy loading: images below the fold load only when they are about to scroll into view.
- Render caching stores built pieces of each page (menus, listings, blocks) and rebuilds only what changed.
- Page cache for anonymous visitors serves most public pages straight from cache; the portal and dashboard are never cached, because they are personal.
Security
A college website holds information about prospective students and families. The rule is simple: private data never reaches a public page.
Database outside the web root
The database file sits in db/ beside web/, not inside it, so no URL can reach it. QA confirmed the old path now returns 404.
Permission-gated staff routes
The dashboard, Site Dev and admin pages each require a named permission. Anonymous visitors get 403, not a hidden link.
Inquiries are never published
Request Info submissions are saved unpublished and are only visible to the Admissions role, enforced in an access hook.
Demo credentials stay local
Demo account passwords live in .credentials.local, which is git-ignored and never leaves the developer’s machine.
One-time login links
Administrators sign in with single-use links from drush uli instead of shared passwords.
Least privilege
Five roles, each with only what its job needs. Only Communications can publish or use full HTML.
Launch checklist
The demo is complete and approved. These are the steps between this build and a real public launch; open items are marked.
- Design approved by the client after the icon revision
- Content model, workflow, roles and permissions built
- All public pages, Hawk Portal and Staff Dashboard tested
- Accessibility checklist reviewed against WCAG 2.2 AA
- Database moved outside the web root
- Configuration exported to
config/syncand backed up to GitHub - To do Production hosting with MySQL or MariaDB and HTTPS
- To do SMTP email so Admissions is notified of new inquiries
- To do Real SIS and single sign-on integration for the Hawk Portal
- To do Real campus photography to replace the AI-generated images
- To do Privacy-friendly analytics and a cookie notice
Palmetto Ridge Junior College is a fictional institution. This case study demonstrates process and deliverables for portfolio purposes.